diff --git a/.gitignore b/.gitignore index b3ca3e50..455e0475 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,9 @@ __pycache__/ *.py[cod] *$py.class +# OSX +*.DS_Store + # C extensions *.so @@ -101,3 +104,7 @@ ENV/ .mypy_cache/ .pytest_cache + + +# VSCode +.vscode/ \ No newline at end of file diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 00000000..4dc4364a --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,29 @@ + +image: python:3.9 + +before_script: + - python --version # For debugging + - pip install virtualenv + - virtualenv venv + - source venv/bin/activate + +.test: + script: + - pip install tox codecov pre-commit + - tox + +test: + extends: .test + variables: + TOXENV: py39 + +deploy: + environment: deploy + script: + - cp $PYPIRC $HOME/.pypirc # get your specific pypi config + - python setup.py bdist_wheel upload -r local-da # replace local-da with your pypi setting + artifacts: + paths: + - dist/*.whl + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH diff --git a/MANIFEST.in b/MANIFEST.in index ecb1f987..6dcbe5c8 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,4 @@ +include python_seed/template/* include python_seed/template/ci/* include python_seed/template/ci/.github/workflows/* include python_seed/template/ci/.circleci/* @@ -5,3 +6,4 @@ include python_seed/template/cov/* include python_seed/template/module/pyseed/* include python_seed/template/module/tests/* include python_seed/template/module/* +include python_seed/template/docs/* diff --git a/README.md b/README.md index 2e0fca24..a2bf3735 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,8 @@ Usage: pyseed create [OPTIONS] NAME Create new python seed skeleton. Options: - --ci [circleci|github] Add CI configuration + --ci [circleci|github|gitlab] Add CI configuration. + --docs Add sphinx docs starter. --help Show this message and exit. ``` @@ -131,7 +132,7 @@ Issues and pull requests are more than welcome. ```bash $ git clone https://github.com/developmentseed/python-seed.git $ cd python-seed -$ pip install -e .[dev] +$ pip install -e ".[dev]" ``` **Python3.7 only** diff --git a/python_seed/scripts/cli.py b/python_seed/scripts/cli.py index 18381e5d..fcb3cf19 100644 --- a/python_seed/scripts/cli.py +++ b/python_seed/scripts/cli.py @@ -21,26 +21,53 @@ def pyseed(): pass +CI_CHOICES = ["circleci", "github", "gitlab"] + @pyseed.command(short_help="Create new python seed skeleton") @click.argument("name", type=str, nargs=1) @click.option( - "--ci", type=click.Choice(["circleci", "github"]), help="Add CI configuration" + "--ci", type=click.Choice(CI_CHOICES), help="Add CI configuration" +) +@click.option( + "--docs", is_flag=True, help="Add Sphinx Docs" ) -def create(name, ci): +def create(name, ci, docs): """Create new python seed skeleton.""" template_dir = str(resources_files("python_seed") / "template" / "module") - shutil.copytree(template_dir, name) + shutil.rmtree(f"{name}/{name}", ignore_errors=True) + shutil.rmtree(f"{name}/docs", ignore_errors=True) + shutil.copytree(template_dir, name, dirs_exist_ok=True) + + gitignore = str(resources_files("python_seed") / "template" / ".gitignore") + shutil.copy2(gitignore, f"{name}/.gitignore") if ci: - template_dir = str( - resources_files("python_seed") / "template" / "ci" / f".{ci}" - ) - shutil.copytree(template_dir, f"{name}/.{ci}") + # acommodate gitlab's single file ci config + if ci == 'gitlab': + template_file = str( + resources_files("python_seed") / "template" / "ci" / ".gitlab-ci.yml" + ) + shutil.copy2(template_file, f"{name}/.gitlab-ci.yml") + else: + template_dir = str( + resources_files("python_seed") / "template" / "ci" / f".{ci}" + ) + shutil.copytree(template_dir, f"{name}/.{ci}", dirs_exist_ok=True) covconfig = str( resources_files("python_seed") / "template" / "cov" / "codecov.yml" ) shutil.copy2(covconfig, f"{name}/codecov.yml") + + if docs: + docs_dir = str( + resources_files("python_seed") / "template" / "docs" + ) + shutil.copytree(docs_dir, f"{name}/docs", dirs_exist_ok=True) + + + + new_dir = name name = name.replace("-", "_") @@ -50,10 +77,11 @@ def create(name, ci): for root, _, files in os.walk(new_dir): for filename in files: - if filename.endswith(".pyc"): - continue - with open(f"{root}/{filename}", "r", encoding="utf-8") as f: - s = f.read().replace("pyseed", name) + try: + with open(f"{root}/{filename}", "r", encoding="utf-8") as f: + s = f.read().replace("pyseed", name) - with open(f"{root}/{filename}", "w", encoding="utf-8") as f: - f.write(s) + with open(f"{root}/{filename}", "w", encoding="utf-8") as f: + f.write(s) + except UnicodeDecodeError: + pass diff --git a/python_seed/template/.gitignore b/python_seed/template/.gitignore new file mode 100644 index 00000000..b4636118 --- /dev/null +++ b/python_seed/template/.gitignore @@ -0,0 +1,109 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# OSX +*.DS_Store + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# 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/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +.pytest_cache + +# VSCode +.vscode/ diff --git a/python_seed/template/ci/.gitlab-ci.yml b/python_seed/template/ci/.gitlab-ci.yml new file mode 100644 index 00000000..b0feeac9 --- /dev/null +++ b/python_seed/template/ci/.gitlab-ci.yml @@ -0,0 +1,62 @@ + +image: python:3.9 + +before_script: + - python --version # For debugging + - pip install virtualenv + - virtualenv venv + - source venv/bin/activate + +.test: + script: + - pip install tox codecov pre-commit + - tox + +test: + extends: .test + variables: + TOXENV: py39 + +deploy: + environment: deploy + script: + - cp $PYPIRC $HOME/.pypirc # get your specific pypi config + - python setup.py bdist_wheel upload -r local-da # replace local-da with your pypi setting + artifacts: + paths: + - dist/*.whl + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + +pages: + script: + - pip install sphinx sphinx-rtd-theme myst-parser + - cd docs ; make html + - mv _build/html/ ../public/ + artifacts: + paths: + - public + rules: + - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + + +# py3.6-test: +# extends: .test +# image: python:3.6 +# variables: +# TOXENV: py36 + +# py3.7-test: +# extends: .test +# image: python:3.7 +# variables: +# TOXENV: py37 + +# py3.8-test: +# extends: .test +# image: python:3.8 +# variables: +# TOXENV: py38 + + + diff --git a/python_seed/template/docs/Makefile b/python_seed/template/docs/Makefile new file mode 100644 index 00000000..d4bb2cbb --- /dev/null +++ b/python_seed/template/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/python_seed/template/docs/conf.py b/python_seed/template/docs/conf.py new file mode 100644 index 00000000..2505ffe1 --- /dev/null +++ b/python_seed/template/docs/conf.py @@ -0,0 +1,73 @@ +# Configuration file for the Sphinx documentation builder. +# +# This file only contains a selection of the most common options. For a full +# list see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('..')) + + +# -- Project information ----------------------------------------------------- + +project = 'pyseed' +copyright = '2022, aofl-data' +author = 'aofl-data' + +# The short X.Y version +version = '0.0.1' + +# The full version, including alpha/beta/rc tags +release = '0.0.1' + + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.coverage', + 'sphinx.ext.napoleon', + 'myst_parser' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = 'en' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + + +# -- Extension configuration ------------------------------------------------- \ No newline at end of file diff --git a/python_seed/template/docs/index.rst b/python_seed/template/docs/index.rst new file mode 100644 index 00000000..51bd0d03 --- /dev/null +++ b/python_seed/template/docs/index.rst @@ -0,0 +1,15 @@ + +.. include:: ../README.md + :parser: myst_parser.sphinx_ + + +The rest of this is reST. + +.. automodule:: pyseed.app + :members: + + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + diff --git a/python_seed/template/docs/make.bat b/python_seed/template/docs/make.bat new file mode 100644 index 00000000..153be5e2 --- /dev/null +++ b/python_seed/template/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/python_seed/template/module/README.md b/python_seed/template/module/README.md index 1348c615..b8c4d2e1 100644 --- a/python_seed/template/module/README.md +++ b/python_seed/template/module/README.md @@ -1 +1,3 @@ # pyseed + +This is markdown imported from the README.md. diff --git a/python_seed/template/module/pyseed/app.py b/python_seed/template/module/pyseed/app.py index b6e90836..3502b1d5 100644 --- a/python_seed/template/module/pyseed/app.py +++ b/python_seed/template/module/pyseed/app.py @@ -1,6 +1,57 @@ -"""pyseed.app: Skeleton of a function.""" +""" +pyseed.app +==== +This is from the file docstring. +""" -def main(arg_one: str, arg_two: int): - """Main function.""" + +def dup_strings(arg_one: str, arg_two: int): + """ + Return a repeated string. This is the main function docstring. + + Parameters + ---------- + + arg_one + A string that should be repeated. + + arg_two + A integer of the number of times `arg_one` should be repeated. + + >>> dup_strings('A', 3) + 'AAA' + """ return arg_one * arg_two + + +class Pizza: + """A delicious object.""" + + def __init__(self, size: int = 16): + """ + Initialize pizzas with a size. + + Parameters + ---------- + + size + Diameter in inchs. + + """ + self.size = size + self.cheese = False + + def add_cheese(self): + """ + Adds cheese. + + >>> pizza = Pizza() + >>> pizza.cheese + False + >>> pizza.add_cheese() + >>> pizza.cheese + True + + """ + self.cheese = True diff --git a/python_seed/template/module/pyseed/scripts/cli.py b/python_seed/template/module/pyseed/scripts/cli.py index 674691d0..15d849fd 100644 --- a/python_seed/template/module/pyseed/scripts/cli.py +++ b/python_seed/template/module/pyseed/scripts/cli.py @@ -9,7 +9,7 @@ @click.version_option(version=__version__, message="%(version)s") def pyseed(): """pyseed subcommands.""" - pass + print(f"pyseed {__version__} is installed.") # @pyseed.command(short_help="Validate COGEO") diff --git a/python_seed/template/module/setup.py b/python_seed/template/module/setup.py index 0106cf26..49751640 100644 --- a/python_seed/template/module/setup.py +++ b/python_seed/template/module/setup.py @@ -24,8 +24,6 @@ python_requires=">=3", classifiers=[ "Intended Audience :: Information Technology", - "Intended Audience :: Science/Research", - "License :: OSI Approved :: BSD License", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", diff --git a/python_seed/template/module/tests/test_function.py b/python_seed/template/module/tests/test_function.py index a2a89c23..c0c36a01 100644 --- a/python_seed/template/module/tests/test_function.py +++ b/python_seed/template/module/tests/test_function.py @@ -4,5 +4,5 @@ def test_app(): - """Test app.main function.""" - assert app.main("ah ", 3) == "ah ah ah " + """Test app.dup_strings function.""" + assert app.dup_strings("ah ", 3) == "ah ah ah " diff --git a/python_seed/template/module/tests/test_mod.py b/python_seed/template/module/tests/test_mod.py index 7b3126eb..ec0f8194 100644 --- a/python_seed/template/module/tests/test_mod.py +++ b/python_seed/template/module/tests/test_mod.py @@ -5,4 +5,4 @@ def test_version(): """test version.""" - assert pyseed.version + assert pyseed.__version__ diff --git a/python_seed/template/module/tox.ini b/python_seed/template/module/tox.ini index 352ad6fc..41306ef8 100644 --- a/python_seed/template/module/tox.ini +++ b/python_seed/template/module/tox.ini @@ -6,6 +6,9 @@ extras = test commands= python -m pytest --cov pyseed --cov-report xml --cov-report term-missing --ignore=venv +[pytest] +addopts = --doctest-modules + # Release tooling [testenv:build] basepython = python3 @@ -27,4 +30,4 @@ deps = twine >= 1.5.0 commands = {[testenv:build]commands} - twine upload --skip-existing dist/* + twine upload --skip-existing dist/* \ No newline at end of file