From bda31cf4cef5946ed72b64160e2aa244fb4c5d69 Mon Sep 17 00:00:00 2001 From: Jeffrey Phillips Freeman Date: Tue, 5 Mar 2024 00:04:11 -0500 Subject: [PATCH] Added boilerplate code for python --- .bumpversion.cfg | 10 +++ .cookiecutterrc | 49 ++++++++++++ .coveragerc | 14 ++++ .python-version | 1 + .travis.yml | 45 +++++++++++ Dockerfile | 48 ++++++++++++ MANIFEST.in | 25 ++++++ ci/bootstrap.py | 65 ++++++++++++++++ ci/templates/.travis.yml | 38 +++++++++ ci/templates/tox.ini | 138 +++++++++++++++++++++++++++++++++ docker-compose.yml | 5 ++ docs/authors.rst | 1 + docs/changelog.rst | 1 + docs/conf.py | 54 +++++++++++++ docs/contributing.rst | 1 + docs/index.rst | 22 ++++++ docs/installation.rst | 7 ++ docs/readme.rst | 1 + docs/reference/boilerplate.rst | 9 +++ docs/reference/index.rst | 7 ++ docs/requirements.txt | 3 + docs/spelling_wordlist.txt | 11 +++ docs/usage.rst | 7 ++ setup.cfg | 77 ++++++++++++++++++ setup.py | 75 ++++++++++++++++++ src/boilerplate/__init__.py | 1 + src/boilerplate/__main__.py | 14 ++++ src/boilerplate/cli.py | 23 ++++++ tests/test_boilerplate.py | 12 +++ tox.ini | 128 ++++++++++++++++++++++++++++++ 30 files changed, 892 insertions(+) create mode 100644 .bumpversion.cfg create mode 100644 .cookiecutterrc create mode 100644 .coveragerc create mode 100644 .python-version create mode 100644 .travis.yml create mode 100644 Dockerfile create mode 100644 MANIFEST.in create mode 100755 ci/bootstrap.py create mode 100644 ci/templates/.travis.yml create mode 100644 ci/templates/tox.ini create mode 100644 docker-compose.yml create mode 100644 docs/authors.rst create mode 100644 docs/changelog.rst create mode 100644 docs/conf.py create mode 100644 docs/contributing.rst create mode 100644 docs/index.rst create mode 100644 docs/installation.rst create mode 100644 docs/readme.rst create mode 100644 docs/reference/boilerplate.rst create mode 100644 docs/reference/index.rst create mode 100644 docs/requirements.txt create mode 100644 docs/spelling_wordlist.txt create mode 100644 docs/usage.rst create mode 100644 setup.cfg create mode 100644 setup.py create mode 100644 src/boilerplate/__init__.py create mode 100644 src/boilerplate/__main__.py create mode 100644 src/boilerplate/cli.py create mode 100644 tests/test_boilerplate.py create mode 100644 tox.ini diff --git a/.bumpversion.cfg b/.bumpversion.cfg new file mode 100644 index 0000000..7a48aa4 --- /dev/null +++ b/.bumpversion.cfg @@ -0,0 +1,10 @@ +[bumpversion] +current_version = 0.1.0 +commit = True +tag = True + +[bumpversion:file:setup.py] + +[bumpversion:file:docs/conf.py] + +[bumpversion:file:src/stockstack/__init__.py] diff --git a/.cookiecutterrc b/.cookiecutterrc new file mode 100644 index 0000000..73b4f70 --- /dev/null +++ b/.cookiecutterrc @@ -0,0 +1,49 @@ +# This file exists so you can easily regenerate your project. +# +# `cookiepatcher` is a convenient shim around `cookiecutter` +# for regenerating projects (it will generate a .cookiecutterrc +# automatically for any template). To use it: +# +# pip install cookiepatcher +# cookiepatcher gh:ionelmc/cookiecutter-pylibrary project-path +# +# See: +# https://pypi.python.org/pypi/cookiecutter +# +# Alternatively, you can run: +# +# cookiecutter --overwrite-if-exists --config-file=project-path/.cookiecutterrc gh:ionelmc/cookiecutter-pylibrary + +default_context: + + appveyor: 'no' + c_extension_cython: 'no' + c_extension_optional: 'no' + c_extension_support: 'no' + codacy: 'yes' + codeclimate: 'yes' + codecov: 'yes' + command_line_interface: 'click' + command_line_interface_bin_name: 'stockstack' + coveralls: 'yes' + distribution_name: 'stockstack' + email: 'freemo@gmail.com' + full_name: 'Jeffrey Phillips Freeman' + github_username: 'stockstack' + landscape: 'yes' + package_name: 'stockstack' + project_name: 'StockStack' + project_short_description: 'StockStack reference implementation' + release_date: '2016-3-19' + repo_name: 'stockstack' + requiresio: 'yes' + scrutinizer: 'yes' + sphinx_doctest: 'yes' + sphinx_theme: 'sphinx-py3doc-enhanced-theme' + test_matrix_configurator: 'yes' + test_matrix_separate_coverage: 'yes' + test_runner: 'pytest' + travis: 'yes' + version: '0.1.0' + website: 'http://JeffreyFreeman.me' + year: 'now' diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..770e36e --- /dev/null +++ b/.coveragerc @@ -0,0 +1,14 @@ +[paths] +source = src + +[run] +branch = true +source = + src + tests +parallel = true + +[report] +show_missing = true +precision = 2 +omit = *migrations* diff --git a/.python-version b/.python-version new file mode 100644 index 0000000..a5c4c76 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.9.0 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..e921384 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,45 @@ +language: python +python: '3.9' +sudo: false +env: + global: + - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so + - SEGFAULT_SIGNALS=all + matrix: + - TOXENV=check + - TOXENV=docs + + - TOXENV=2.7-cover,coveralls,codecov + - TOXENV=2.7-nocov + - TOXENV=3.3-cover,coveralls,codecov + - TOXENV=3.3-nocov + - TOXENV=3.4-cover,coveralls,codecov + - TOXENV=3.4-nocov + - TOXENV=3.5-cover,coveralls,codecov + - TOXENV=3.5-nocov + - TOXENV=pypy-cover,coveralls,codecov + - TOXENV=pypy-nocov +before_install: + - python --version + - uname -a + - lsb_release -a +install: + - pip install tox + - virtualenv --version + - easy_install --version + - pip --version + - tox --version +script: + - tox -v +after_failure: + - more .tox/log/* | cat + - more .tox/*/log/* | cat +before_cache: + - rm -rf $HOME/.cache/pip/log +cache: + directories: + - $HOME/.cache/pip +notifications: + email: + on_success: never + on_failure: always diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1fe259d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,48 @@ +FROM python:3 + +LABEL maintainer="Jeffrey Phillips Freeman jeffrey.freeman@cleverthis.com" + +ENV PYENV_ROOT="/.pyenv" \ + PATH="/.pyenv/bin:/.pyenv/shims:$PATH" + +RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash + +RUN apt update -y && \ + apt-get upgrade -y && \ + apt-get dist-upgrade -y && \ + apt-get install -y --no-install-recommends \ + libssl-dev \ + libreadline-gplv2-dev \ + libncursesw5-dev \ + libssl-dev \ + libsqlite3-dev \ + tk-dev \ + libgdbm-dev \ + libc6-dev \ + libbz2-dev \ + nano && \ + apt-get clean && \ + rm -r /var/lib/apt/lists/* + +#RUN pyenv install 2.7.18 && \ +# pyenv install 3.3.7 && \ +# pyenv install 3.4.10 && \ +# pyenv install 3.5.10 && \ +# pyenv install 3.9.0 && \ +# pyenv install pypy-5.7.1 + +RUN pyenv install 3.9.0 && \ + pyenv install 2.7.18 && \ + pyenv global 2.7.18 && \ + pyenv global 3.9.0 +RUN /.pyenv/versions/3.9.0/bin/python3.9 -m pip install --upgrade pip +RUN pip install tox + +RUN mkdir -p /usr/src/boilerplate && \ + chmod a+rwx -R /usr/src/boilerplate && \ + mkdir /.cache && \ + chmod a+rwx /.cache && \ + mkdir /.tox && \ + chmod a+rwx /.tox + +VOLUME /usr/src/boilerplate diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..3290df2 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,25 @@ +graft docs +graft examples +graft src +graft ci +graft tests + +include .bumpversion.cfg +include .coveragerc +include .cookiecutterrc +include .editorconfig +include .isort.cfg + +include AUTHORS.rst +include CHANGELOG.rst +include CONTRIBUTING.rst +include LICENSE +include README.rst + +include tox.ini .travis.yml appveyor.yml + +include docker-compose.yml +include Dockerfile +include .python-version + +global-exclude *.py[cod] __pycache__ *.so *.dylib diff --git a/ci/bootstrap.py b/ci/bootstrap.py new file mode 100755 index 0000000..a5709f9 --- /dev/null +++ b/ci/bootstrap.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +from __future__ import absolute_import, print_function, unicode_literals + +import os +import sys +from os.path import abspath +from os.path import dirname +from os.path import exists +from os.path import join + + +if __name__ == "__main__": + base_path = dirname(dirname(abspath(__file__))) + print("Project path: {0}".format(base_path)) + env_path = join(base_path, ".tox", "bootstrap") + if sys.platform == "win32": + bin_path = join(env_path, "Scripts") + else: + bin_path = join(env_path, "bin") + if not exists(env_path): + import subprocess + + print("Making bootstrap env in: {0} ...".format(env_path)) + try: + subprocess.check_call(["virtualenv", env_path]) + except subprocess.CalledProcessError: + subprocess.check_call([sys.executable, "-m", "virtualenv", env_path]) + print("Installing `jinja2` and `matrix` into bootstrap environment...") + subprocess.check_call([join(bin_path, "pip"), "install", "jinja2", "matrix"]) + activate = join(bin_path, "activate_this.py") + # noinspection PyCompatibility + exec(compile(open(activate, "rb").read(), activate, "exec"), dict(__file__=activate)) + + import jinja2 + + import matrix + + jinja = jinja2.Environment( + loader=jinja2.FileSystemLoader(join(base_path, "ci", "templates")), + trim_blocks=True, + lstrip_blocks=True, + keep_trailing_newline=True + ) + + tox_environments = {} + for (alias, conf) in matrix.from_file(join(base_path, "setup.cfg")).items(): + python = conf["python_versions"] + deps = conf["dependencies"] + tox_environments[alias] = { + "python": "python" + python if "py" not in python else python, + "deps": deps.split(), + } + if "coverage_flags" in conf: + cover = {"false": False, "true": True}[conf["coverage_flags"].lower()] + tox_environments[alias].update(cover=cover) + if "environment_variables" in conf: + env_vars = conf["environment_variables"] + tox_environments[alias].update(env_vars=env_vars.split()) + + for name in os.listdir(join("ci", "templates")): + with open(join(base_path, name), "w") as fh: + fh.write(jinja.get_template(name).render(tox_environments=tox_environments)) + print("Wrote {}".format(name)) + print("DONE.") diff --git a/ci/templates/.travis.yml b/ci/templates/.travis.yml new file mode 100644 index 0000000..a7f4187 --- /dev/null +++ b/ci/templates/.travis.yml @@ -0,0 +1,38 @@ +language: python +python: '3.5' +sudo: false +env: + global: + - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so + - SEGFAULT_SIGNALS=all + matrix: + - TOXENV=check + - TOXENV=docs +{% for env, config in tox_environments|dictsort %}{{ '' }} + - TOXENV={{ env }}{% if config.cover %},coveralls,codecov{% endif -%} +{% endfor %} + +before_install: + - python --version + - uname -a + - lsb_release -a +install: + - pip install tox + - virtualenv --version + - easy_install --version + - pip --version + - tox --version +script: + - tox -v +after_failure: + - more .tox/log/* | cat + - more .tox/*/log/* | cat +before_cache: + - rm -rf $HOME/.cache/pip/log +cache: + directories: + - $HOME/.cache/pip +notifications: + email: + on_success: never + on_failure: always diff --git a/ci/templates/tox.ini b/ci/templates/tox.ini new file mode 100644 index 0000000..e8235b4 --- /dev/null +++ b/ci/templates/tox.ini @@ -0,0 +1,138 @@ +[tox] +envlist = + clean, + check, +{% for env in tox_environments|sort %} + {{ env }}, +{% endfor %} + report, + docs + +[testenv] +basepython = + {docs,spell}: python2.7 + {clean,check,report,extension-coveralls,coveralls,codecov}: python3.5 +setenv = + PYTHONPATH={toxinidir}/tests + PYTHONUNBUFFERED=yes +passenv = + * +deps = + pytest + pytest-travis-fold +commands = + {posargs:py.test -vv --ignore=src} + +[testenv:spell] +setenv = + SPELLCHECK=1 +commands = + sphinx-build -b spelling docs dist/docs +skip_install = true +usedevelop = false +deps = + -r{toxinidir}/docs/requirements.txt + sphinxcontrib-spelling + pyenchant + +[testenv:docs] +deps = + -r{toxinidir}/docs/requirements.txt +commands = + sphinx-build {posargs:-E} -b html docs dist/docs + sphinx-build -b linkcheck docs dist/docs + +[testenv:bootstrap] +deps = + jinja2 + matrix +skip_install = true +usedevelop = false +commands = + python ci/bootstrap.py +passenv = + * + +[testenv:check] +deps = + docutils + check-manifest + flake8 + readme-renderer + pygments + isort +skip_install = true +usedevelop = false +commands = + python setup.py check --strict --metadata --restructuredtext + check-manifest {toxinidir} + flake8 src tests setup.py + isort --verbose --check-only --diff --recursive src tests setup.py + +[testenv:coveralls] +deps = + coveralls +skip_install = true +usedevelop = false +commands = + coverage combine --append + coverage report + coveralls [] + +[testenv:codecov] +deps = + codecov +skip_install = true +usedevelop = false +commands = + coverage combine --append + coverage report + coverage xml --ignore-errors + codecov [] + + +[testenv:report] +deps = coverage +skip_install = true +usedevelop = false +commands = + coverage combine --append + coverage report + coverage html + +[testenv:clean] +commands = coverage erase +skip_install = true +usedevelop = false +deps = coverage + +{% for env, config in tox_environments|dictsort %} +[testenv:{{ env }}] +basepython = {env:TOXPYTHON:{{ config.python }}} +{% if config.cover or config.env_vars %} +setenv = + {[testenv]setenv} +{% endif %} +{% for var in config.env_vars %} + {{ var }} +{% endfor %} +{% if config.cover %} + WITH_COVERAGE=yes +usedevelop = true +commands = + {posargs:py.test --cov --cov-report=term-missing -vv} +{% endif %} +{% if config.cover or config.deps %} +deps = + {[testenv]deps} +{% endif %} +{% if config.cover %} + pytest-cov +{% endif %} +{% for dep in config.deps %} + {{ dep }} +{% endfor %} + +{% endfor %} + + diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..3910a9b --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,5 @@ +version: '2' +services: + boilerplate: + image: boilerplate/boilerplate:latest + build: . diff --git a/docs/authors.rst b/docs/authors.rst new file mode 100644 index 0000000..bcfd9cb --- /dev/null +++ b/docs/authors.rst @@ -0,0 +1 @@ +.. include:: ../AUTHORS.md diff --git a/docs/changelog.rst b/docs/changelog.rst new file mode 100644 index 0000000..669aaa2 --- /dev/null +++ b/docs/changelog.rst @@ -0,0 +1 @@ +.. include:: ../CHANGELOG.md diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000..29b18c7 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import os + + +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.coverage', + 'sphinx.ext.doctest', + 'sphinx.ext.extlinks', + 'sphinx.ext.ifconfig', + 'sphinx.ext.napoleon', + 'sphinx.ext.todo', + 'sphinx.ext.viewcode', +] +if os.getenv('SPELLCHECK'): + extensions += 'sphinxcontrib.spelling', + spelling_show_suggestions = True + spelling_lang = 'en_US' + +source_suffix = '.rst' +master_doc = 'index' +project = u'Boilerplate' +year = '2024' +author = u'Jeffrey Phillips Freeman' +copyright = '{0}, {1}'.format(year, author) +version = release = u'0.1.0' + +pygments_style = 'trac' +templates_path = ['.'] +extlinks = { + 'issue': ('https://git.cleverthis.com/cleverthis/base/base-python/-/issues%s', '#'), + 'pr': ('https://git.cleverthis.com/cleverthis/base/base-python/-/merge_requests%s', 'PR #'), +} +import sphinx_py3doc_enhanced_theme +html_theme = "sphinx_py3doc_enhanced_theme" +html_theme_path = [sphinx_py3doc_enhanced_theme.get_html_theme_path()] +html_theme_options = { + 'githuburl': 'https://git.cleverthis.com/cleverthis/base/base-python' +} + +html_use_smartypants = True +html_last_updated_fmt = '%b %d, %Y' +html_split_index = False +html_sidebars = { + '**': ['searchbox.html', 'globaltoc.html', 'sourcelink.html'], +} +html_short_title = '%s-%s' % (project, version) + +napoleon_use_ivar = True +napoleon_use_rtype = False +napoleon_use_param = False diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 0000000..58977a8 --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1 @@ +.. include:: ../CONTRIBUTING.md diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..40f35b5 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,22 @@ +======== +Contents +======== + +.. toctree:: + :maxdepth: 2 + + readme + installation + usage + reference/index + contributing + authors + changelog + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` + diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..0386e16 --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,7 @@ +============ +Installation +============ + +At the command line:: + + pip install boilerplate diff --git a/docs/readme.rst b/docs/readme.rst new file mode 100644 index 0000000..bdff72a --- /dev/null +++ b/docs/readme.rst @@ -0,0 +1 @@ +.. include:: ../README.md diff --git a/docs/reference/boilerplate.rst b/docs/reference/boilerplate.rst new file mode 100644 index 0000000..7a4859b --- /dev/null +++ b/docs/reference/boilerplate.rst @@ -0,0 +1,9 @@ +boilerplate +========== + +.. testsetup:: + + from boilerplate import * + +.. automodule:: boilerplate + :members: diff --git a/docs/reference/index.rst b/docs/reference/index.rst new file mode 100644 index 0000000..6014705 --- /dev/null +++ b/docs/reference/index.rst @@ -0,0 +1,7 @@ +Reference +========= + +.. toctree:: + :glob: + + boilerplate* diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..ef4a013 --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +sphinx>=1.3 +sphinx-py3doc-enhanced-theme +-e . diff --git a/docs/spelling_wordlist.txt b/docs/spelling_wordlist.txt new file mode 100644 index 0000000..f95eb78 --- /dev/null +++ b/docs/spelling_wordlist.txt @@ -0,0 +1,11 @@ +builtin +builtins +classmethod +staticmethod +classmethods +staticmethods +args +kwargs +callstack +Changelog +Indices diff --git a/docs/usage.rst b/docs/usage.rst new file mode 100644 index 0000000..28c6c9b --- /dev/null +++ b/docs/usage.rst @@ -0,0 +1,7 @@ +===== +Usage +===== + +To use Boilerplate in a project:: + + import boilerplate diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..ab51977 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,77 @@ +[bdist_wheel] +universal = 1 + +[flake8] +max-line-length = 140 +exclude = tests/*,*/migrations/*,*/south_migrations/* + +[tool:pytest] +norecursedirs = + .git + .tox + .env + dist + build + south_migrations + migrations +python_files = + test_*.py + *_test.py + tests.py +addopts = + -rxEfsw + --strict + --ignore=docs/conf.py + --ignore=setup.py + --ignore=ci + --ignore=.eggs + --doctest-modules + --doctest-glob=\*.rst + --tb=short + +[isort] +force_single_line=True +line_length=120 +known_first_party=boilerplate +default_section=THIRDPARTY +forced_separate=test_boilerplate +not_skip = __init__.py +skip = migrations, south_migrations + +[matrix] +# This is the configuration for the `./bootstrap.py` script. +# It generates `.travis.yml`, `tox.ini` and `appveyor.yml`. +# +# Syntax: [alias:] value [!variable[glob]] [&variable[glob]] +# +# alias: +# - is used to generate the tox environment +# - it's optional +# - if not present the alias will be computed from the `value` +# value: +# - a value of "-" means empty +# !variable[glob]: +# - exclude the combination of the current `value` with +# any value matching the `glob` in `variable` +# - can use as many you want +# &variable[glob]: +# - only include the combination of the current `value` +# when there's a value matching `glob` in `variable` +# - can use as many you want + +python_versions = + 3.9 + +dependencies = +# 1.4: Django==1.4.16 !python_versions[3.*] +# 1.5: Django==1.5.11 +# 1.6: Django==1.6.8 +# 1.7: Django==1.7.1 !python_versions[2.6] +# Deps commented above are provided as examples. That's what you would use in a Django project. + +coverage_flags = + cover: true + nocov: false + +environment_variables = + - diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..71c7c5f --- /dev/null +++ b/setup.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- +from __future__ import absolute_import +from __future__ import print_function + +import io +import re +from glob import glob +from os.path import basename +from os.path import dirname +from os.path import join +from os.path import splitext + +from setuptools import find_packages +from setuptools import setup + + +def read(*names, **kwargs): + return io.open( + join(dirname(__file__), *names), + encoding=kwargs.get('encoding', 'utf8') + ).read() + + +setup( + name='boilerplate', + version='0.1.0', + license='Apache', + description='A starter project for Python', + long_description='%s\n%s' % ( + re.compile('^.. start-badges.*^.. end-badges', re.M | re.S).sub('', read('README.rst')), + re.sub(':[a-z]+:`~?(.*?)`', r'``\1``', read('CHANGELOG.rst')) + ), + author='CleverThis', + author_email='jeffrey.freeman@cleverthis.com', + url='https://git.cleverthis.com/cleverthis/base/base-python', + packages=find_packages('src'), + package_dir={'': 'src'}, + py_modules=[splitext(basename(path))[0] for path in glob('src/*.py')], + include_package_data=True, + zip_safe=False, + classifiers=[ + # complete classifier list: http://pypi.python.org/pypi?%3Aaction=list_classifiers + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'License :: OSI Approved :: Apache License', + 'Operating System :: Unix', + 'Operating System :: POSIX', + 'Operating System :: Microsoft :: Windows', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: Implementation :: CPython', + # uncomment if you test on these interpreters: + # 'Programming Language :: Python :: Implementation :: IronPython', + # 'Programming Language :: Python :: Implementation :: Jython', + # 'Programming Language :: Python :: Implementation :: Stackless', + 'Topic :: Utilities', + ], + keywords=[ + # eg: 'keyword1', 'keyword2', 'keyword3', + ], + install_requires=[ + 'click', + ], + extras_require={ + # eg: + # 'rst': ['docutils>=0.11'], + # ':python_version=="2.6"': ['argparse'], + }, + entry_points={ + 'console_scripts': [ + 'boilerplate = boilerplate.cli:main', + ] + }, +) diff --git a/src/boilerplate/__init__.py b/src/boilerplate/__init__.py new file mode 100644 index 0000000..3dc1f76 --- /dev/null +++ b/src/boilerplate/__init__.py @@ -0,0 +1 @@ +__version__ = "0.1.0" diff --git a/src/boilerplate/__main__.py b/src/boilerplate/__main__.py new file mode 100644 index 0000000..7260eff --- /dev/null +++ b/src/boilerplate/__main__.py @@ -0,0 +1,14 @@ +""" +Entrypoint module, in case you use `python -mboilerplate`. + + +Why does this file exist, and why __main__? For more info, read: + +- https://www.python.org/dev/peps/pep-0338/ +- https://docs.python.org/2/using/cmdline.html#cmdoption-m +- https://docs.python.org/3/using/cmdline.html#cmdoption-m +""" +from boilerplate.cli import main + +if __name__ == "__main__": + main() diff --git a/src/boilerplate/cli.py b/src/boilerplate/cli.py new file mode 100644 index 0000000..37ce223 --- /dev/null +++ b/src/boilerplate/cli.py @@ -0,0 +1,23 @@ +""" +Module that contains the command line app. + +Why does this file exist, and why not put this in __main__? + + You might be tempted to import things from __main__ later, but that will cause + problems: the code will get executed twice: + + - When you run `python -mboilerplate` python will execute + ``__main__.py`` as a script. That means there won't be any + ``boilerplate.__main__`` in ``sys.modules``. + - When you import __main__ it will get executed again (as a module) because + there's no ``boilerplate.__main__`` in ``sys.modules``. + + Also see (1) from http://click.pocoo.org/5/setuptools/#setuptools-integration +""" +import click + + +@click.command() +@click.argument('names', nargs=-1) +def main(names): + click.echo(repr(names)) diff --git a/tests/test_boilerplate.py b/tests/test_boilerplate.py new file mode 100644 index 0000000..4884615 --- /dev/null +++ b/tests/test_boilerplate.py @@ -0,0 +1,12 @@ + +from click.testing import CliRunner + +from boilerplate.cli import main + + +def test_main(): + runner = CliRunner() + result = runner.invoke(main, []) + + assert result.output == '()\n' + assert result.exit_code == 0 diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..5fb5b6b --- /dev/null +++ b/tox.ini @@ -0,0 +1,128 @@ +[tox] +envlist = + clean, + build, + check, + 3.9-cover, + 3.9-nocov, + report, + docs + +[testenv] +basepython = + {clean,check,report,extension-coveralls,coveralls,codecov,docs,spell,build}: python3.9 +setenv = + PYTHONPATH={toxinidir}/tests + PYTHONUNBUFFERED=yes +passenv = + * +deps = + pytest + pytest-travis-fold +commands = + {posargs:py.test -vv --ignore=src} + +[testenv:spell] +setenv = + SPELLCHECK=1 +commands = + sphinx-build -b spelling docs build/docs +skip_install = true +usedevelop = false +deps = + -r{toxinidir}/docs/requirements.txt + sphinxcontrib-spelling + pyenchant + +[testenv:docs] +deps = + -r{toxinidir}/docs/requirements.txt +commands = + sphinx-build {posargs:-E} -b html docs build/docs + #sphinx-build -b linkcheck docs build/docs + sphinx-build docs build/docs + +[testenv:bootstrap] +deps = + jinja2 + matrix +skip_install = true +usedevelop = false +commands = + python ci/bootstrap.py +passenv = + * + +[testenv:build] +commands = + python setup.py sdist bdist_wheel --universal + +[testenv:check] +deps = + docutils + check-manifest + flake8 + readme-renderer + pygments + isort + twine +skip_install = true +usedevelop = false +commands = + twine check dist/* + check-manifest {toxinidir} + flake8 src tests setup.py + isort --verbose --check-only --diff --recursive src tests setup.py + +[testenv:coveralls] +deps = + coveralls +skip_install = true +usedevelop = false +commands = + - coverage combine --append + coverage report + coveralls [] + +[testenv:codecov] +deps = + codecov +skip_install = true +usedevelop = false +commands = + - coverage combine --append + coverage report + coverage xml --ignore-errors + codecov [] + + +[testenv:report] +deps = coverage +skip_install = true +usedevelop = false +commands = + - coverage combine --append + coverage report + coverage html + +[testenv:clean] +commands = coverage erase +skip_install = true +usedevelop = false +deps = coverage + + +[testenv:3.9-nocov] +basepython = {env:TOXPYTHON:python3.9} + +[testenv:3.9-cover] +basepython = {env:TOXPYTHON:python3.9} +setenv = + {[testenv]setenv} + WITH_COVERAGE=yes +usedevelop = true +commands = + {posargs:py.test --cov --cov-report=term-missing -vv} +deps = + {[testenv]deps} + pytest-cov