diff --git a/.gitchangelog.rc b/.gitchangelog.rc
index 8fddd98..62a2f96 100644
--- a/.gitchangelog.rc
+++ b/.gitchangelog.rc
@@ -61,6 +61,7 @@
ignore_regexps = [
r'^([cC]i)\s*:',
r'dependabot',
+ r'automated change',
r'@minor', r'!minor',
r'@cosmetic', r'!cosmetic',
r'@refactor', r'!refactor',
diff --git a/README.rst b/README.rst
index 7029527..c8cd81a 100644
--- a/README.rst
+++ b/README.rst
@@ -14,11 +14,21 @@ To create a new repository using this template, click the button labeled
|tag| |license| |reuse| |python|
+Template repo cleanup
+~~~~~~~~~~~~~~~~~~~~~
+
After creating your repository, replace the example project name "simple"
with your own:
* change the project name at the top of ``pyproject.toml``
* change the project name in ``docs/source/conf.py`` *and* ``docs/source/index.rst``
+* change the author and copyright names in all the doorstop doc and config files, ie
+
+ + ``find . -name .doorstop.yml`` and review/edit all files
+
+* then replace all the doorstop content with your own project details
+* create more doorstop items as needed, link specific design and test
+ elements back to related **Shall** statements
* change the author details in ``pyproject.toml`` *and* ``docs/source/conf.py``
* change the package directory name under the ``src`` folder
* change the github URL paths in ``pyproject.toml``
@@ -96,11 +106,57 @@ extra features:
Dev tools
-=========
+~~~~~~~~~
Local tool dependencies to aid in development; install them for
maximum enjoyment.
+Doorstop
+--------
+
+Initial configurations and first-item doc stubs have been created in the
+following directories::
+
+ $ tree reqs/ docs/swd/ tests/docs/
+ reqs/
+ ├── .doorstop.yml
+ └── REQ001.yml
+ docs/swd/
+ ├── assets
+ │ ├── .gitkeep
+ │ └── simple_dependency_graph.svg
+ ├── .doorstop.yml
+ └── SDD001.md
+ tests/docs/
+ ├── .doorstop.yml
+ └── TST001.yml
+
+The doorstop tool has been added to project [dev] "extras" as well as the
+tox dev and docs environments. Use the "dev" environment for working with
+doorstop_ documents, eg::
+
+ tox -e dev
+ source .venv/bin/activate
+ (.venv) doorstop
+ building tree...
+ loading documents...
+ validating items...
+ WARNING: SDD: SDD001: unreviewed changes
+
+ REQ
+ │
+ ├── TST
+ │
+ └── SDD
+
+
+Please see the doorstop Quick Start for an overview of the relevant doorstop
+commands.
+
+.. _doorstop Quick Start: https://doorstop.readthedocs.io/en/latest/getting-started/quickstart.html
+.. _doorstop: https://doorstop.readthedocs.io/en/latest/index.html
+
+
Tox
---
@@ -187,7 +243,7 @@ It's usually a good idea to update the hooks to the latest version::
SBOM and license info
-=====================
+~~~~~~~~~~~~~~~~~~~~~
This project is now compliant with the REUSE Specification Version 3.3, so the
corresponding license information for all files can be found in the ``REUSE.toml``
@@ -267,10 +323,10 @@ specifications.
:target: https://www.python.org/downloads/
:alt: Python
-.. |reuse| image:: https://api.reuse.software/badge/git.fsfe.org/reuse/api
- :target: https://api.reuse.software/info/git.fsfe.org/reuse/api
+.. |reuse| image:: https://img.shields.io/badge/REUSE-compliant-blue.svg
+ :target: https://reuse.software/spec-3.3/
:alt: REUSE status
.. |pre| image:: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit&logoColor=white
- :target: https://github.com/pre-commit/pre-commit
- :alt: pre-commit
+ :target: https://github.com/pre-commit/pre-commit
+ :alt: pre-commit
diff --git a/docs/process_md_urls.py b/docs/process_md_urls.py
new file mode 100755
index 0000000..e2ecde2
--- /dev/null
+++ b/docs/process_md_urls.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+
+"""
+Get the path to markdown files and process image URLs based on files in
+args. One or more (SVG or PNG) files are required.
+"""
+import os
+import sys
+from pathlib import Path
+from string import Template
+from typing import List, Tuple
+
+DEBUG = int(os.getenv('DEBUG', default='0'))
+EXTENSIONS = ['.svg', '.png']
+
+FIG_TPL = """```{figure} ${figure_path}
+:width: 90 %
+:align: center
+:alt: ${caption_lc}
+
+${caption_title} (captured from mermaid to SVG or PNG).
+```
+"""
+
+CTX = {
+ 'caption_lc': '',
+ 'caption_title': '',
+ 'figure_path': '',
+}
+
+
+def render_caption(caption: str, path: str):
+ """
+ Render a string template.
+ """
+ CTX.update(
+ {
+ 'caption_lc': caption.lower(),
+ 'caption_title': caption.title(),
+ 'figure_path': path,
+ }
+ )
+ return Template(FIG_TPL).substitute(CTX)
+
+
+def find_mdfiles(
+ start: str = '.', fglob: str = '*.md', excludes: Tuple = ('.github', '.tox', '.venv')
+) -> List:
+ """
+ Find markdown files subject to specified exclude paths.
+
+ :param start: directory to start file search
+ :param fglob: file extension glob
+ :param excludes: tuple of excludes
+ """
+ target_files: List = []
+ files = Path(start).rglob(fglob)
+ for file in list(files):
+ if str(file).startswith(excludes):
+ continue
+ target_files.append(file)
+ if DEBUG:
+ print(f'Found file list: {target_files}')
+ return target_files
+
+
+def process_files(new_files: List, target_files: List):
+ """
+ process files if we found enough of each.
+ """
+ for img_file in new_files:
+ for md_file in target_files:
+ doc_str = Path(md_file).read_text(encoding='utf-8')
+ if Path(img_file).name not in doc_str:
+ continue
+ with Path(md_file).open(encoding='utf-8') as file:
+ lines = file.readlines()
+ with Path(md_file).open(mode='w', encoding='utf-8') as file:
+ for line in lines:
+ if line.startswith(('![', '[')) and Path(img_file).name in line:
+ if DEBUG:
+ print(line)
+ cap_str = line.split('[', 1)[1].split(']')[0]
+ path_str = line.split('(', 1)[1].split(')')[0]
+ text = render_caption(cap_str, path_str)
+ file.write(text + '\n')
+ else:
+ file.write(line)
+
+
+def main(argv: list[str] | None = None) -> None:
+ """
+ Runs the program.
+
+ Args:
+ argv: A list of arguments, not including the prog name.
+ """
+ if not argv:
+ if DEBUG:
+ print("No image files, nothing to do ...")
+ sys.exit(0)
+
+ if DEBUG:
+ print(argv)
+ new_files = [f for f in argv if Path(f).suffix in EXTENSIONS and Path(f).exists()]
+ if len(new_files) < 1:
+ if DEBUG:
+ print(f"No valid input files (only {EXTENSIONS} are allowed)")
+ sys.exit(1)
+ if DEBUG:
+ print(new_files)
+
+ target_files = find_mdfiles()
+ if not target_files:
+ if DEBUG:
+ print("No markdown files, nothing to do ...")
+ sys.exit(0)
+
+ if DEBUG:
+ print(target_files)
+
+ process_files(new_files, target_files)
+
+
+# print(','.join(target_files))
+
+if __name__ == "__main__":
+ main(sys.argv[1:])
diff --git a/docs/source/conf.py b/docs/source/conf.py
index 47a877d..e062be6 100644
--- a/docs/source/conf.py
+++ b/docs/source/conf.py
@@ -3,10 +3,7 @@
from datetime import datetime
-if sys.version_info < (3, 8):
- from importlib_metadata import version
-else:
- from importlib.metadata import version
+from importlib.metadata import version
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..')))
@@ -49,14 +46,20 @@
'sphinx.ext.coverage',
'sphinx.ext.viewcode',
'myst_parser',
+ #'sphinxcontrib.mermaid',
]
+#myst_fence_as_directive = ["mermaid"]
+myst_suppress_warnings = ["myst.header"]
+myst_enable_extensions = ["attrs_inline", "deflist", "fieldlist", "substitution",]
+
# sphinxcontrib.apidoc
apidoc_module_dir = f'../../src/{project}'
apidoc_output_dir = 'api'
apidoc_excluded_paths = ['scripts', 'tests']
apidoc_module_first = True
apidoc_separate_modules = True
+
autodoc_typehints = 'description'
# Add any paths that contain templates here, relative to this directory.
diff --git a/docs/source/ds/.gitignore b/docs/source/ds/.gitignore
new file mode 100644
index 0000000..19a8123
--- /dev/null
+++ b/docs/source/ds/.gitignore
@@ -0,0 +1,2 @@
+*.svg
+/*.md
diff --git a/docs/source/ds/assets/.gitkeep b/docs/source/ds/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 7da97bf..c82995e 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -13,6 +13,9 @@ Simple API and SW Docs
:maxdepth: 1
:caption: Contents:
+ ds/reqs_tree
+ ds/sw_design
+ ds/unit_tests
README
api/modules
dev/generate-changelog
diff --git a/docs/sphinx_prep.sh b/docs/sphinx_prep.sh
new file mode 100755
index 0000000..811bb7a
--- /dev/null
+++ b/docs/sphinx_prep.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+#
+# This removes ToC section from doorstop-generated markdown.
+# We need to cleanup sphinx doc list and quiet MyST warnings.
+
+set -euo pipefail
+
+failures=0
+trap 'failures=$((failures+1))' ERR
+
+FILE_ARG=${1}
+
+echo "Processing markdown file: ${FILE_ARG}"
+sed -i '/^# 1.0/,$!d' $FILE_ARG
+
+if ((failures == 0)); then
+ echo "Success"
+else
+ echo "Something went wrong"
+ exit 1
+fi
diff --git a/docs/swd/.doorstop.yml b/docs/swd/.doorstop.yml
new file mode 100644
index 0000000..a99ee1d
--- /dev/null
+++ b/docs/swd/.doorstop.yml
@@ -0,0 +1,21 @@
+settings:
+ digits: 3
+ itemformat: markdown
+ parent: REQ
+ prefix: SDD
+ sep: ''
+extensions:
+ item_sha_required: true # sha256
+attributes:
+ defaults:
+ doc:
+ name: SW Design
+ title: SW Design Description
+ ref: ''
+ by: tdeveloper
+ major: '1'
+ minor: A
+ copyright: tdeveloper
+ publish:
+ - commentary
+ - rationale
diff --git a/docs/swd/SDD001.md b/docs/swd/SDD001.md
new file mode 100644
index 0000000..d347115
--- /dev/null
+++ b/docs/swd/SDD001.md
@@ -0,0 +1,60 @@
+---
+active: true
+derived: false
+doc:
+ by: tdeveloper
+ copyright: tdeveloper
+ major: '1'
+ minor: A
+ name: SW Design
+ ref: ''
+ title: SW Design Description
+level: 1.0
+links: []
+normative: false
+ref: ''
+reviewed: niwzsx_UYtwjd_p6uGIruhDROomRv8QMNBKnC_2d0Qg=
+---
+
+# Design Elements
+
+The simple package provides a convenient example and baseline project
+structure for demonstrating current packaging standards with dynamic
+versioning using the core setuptools package and default PEP517 build
+backend.
+
+The primary install dependencies are importlib-metadata, doorstop, and
+munch, where doorstop is primarily an offline dependency for managing
+requirements data. Complete package dependencies are shown in the
+figure below:
+
+```{figure} assets/simple_dependency_graph.svg
+:width: 90 %
+:align: center
+:alt: simple software units
+
+Simple Software Units (captured from mermaid to SVG or PNG).
+```
+
+
+ simple_dependency_graph source
+ simple dependency graph showing primary software units.
+
+```
+ graph TB
+ subgraph id1[simple Dependencies]
+ subgraph id2[Python Packages]
+ A(simple)
+ B(importlib-metadata)
+ C(munch)
+ D{doorstop}
+ end
+ end
+ A ==> B & C & D
+ D -.-> A
+```
+
+
+## Design decisions
+
+More text here.
\ No newline at end of file
diff --git a/docs/swd/assets/.gitkeep b/docs/swd/assets/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/docs/swd/assets/simple_dependency_graph.svg b/docs/swd/assets/simple_dependency_graph.svg
new file mode 100644
index 0000000..39e3d4a
--- /dev/null
+++ b/docs/swd/assets/simple_dependency_graph.svg
@@ -0,0 +1,2 @@
+
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index b0e0aa6..37cdd74 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -18,14 +18,15 @@ authors = [
]
classifiers = [
- "Development Status :: 3 - Alpha",
+ "Development Status :: 4 - Beta",
"Environment :: Console",
+ "Framework :: tox",
"Intended Audience :: Developers",
"Operating System :: POSIX :: Linux",
"Operating System :: Unix",
"Programming Language :: Python :: 3",
"Topic :: Documentation",
- "Topic :: Multimedia :: Graphics",
+ "Topic :: Software Development",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Documentation",
"Topic :: Software Development :: Testing",
@@ -40,6 +41,7 @@ requires-python = ">=3.9"
[project.optional-dependencies]
dev = [
+ "doorstop",
"flake8",
"isort",
"mypy>=0.990",
@@ -52,12 +54,12 @@ cov = [
]
doc = [
"sphinx",
- "sphinxcontrib.apidoc",
"sphinx_git",
- "myst-parser",
- "sphinxcontrib.mermaid",
+ "sphinxcontrib.apidoc",
"sphinx_rtd_theme<3.0", # for the version display
"sphinx-nefertiti",
+ "myst-parser",
+ #"sphinxcontrib.mermaid",
]
test = [
"pytest",
@@ -85,7 +87,7 @@ markers = "subscript"
[tool.coverage.run]
branch = true
-source_pkgs = ["src"]
+source_pkgs = ["src/simple"]
omit = [
"setup.py",
"scripts",
diff --git a/reqs/.doorstop.yml b/reqs/.doorstop.yml
new file mode 100644
index 0000000..cfc5f3a
--- /dev/null
+++ b/reqs/.doorstop.yml
@@ -0,0 +1,22 @@
+settings:
+ digits: 3
+ itemformat: yaml
+ prefix: REQ
+ sep: ''
+attributes:
+ reviewed:
+ - short-name
+ defaults:
+ short-name: ''
+ doc:
+ name: simple
+ title: Requirements for _simple_
+ ref: ''
+ by: tdeveloper
+ major: '1'
+ minor: A
+ copyright: tdeveloper
+ publish:
+ - commentary
+ - rationale
+ - normative
diff --git a/reqs/REQ001.yml b/reqs/REQ001.yml
new file mode 100644
index 0000000..c23be5a
--- /dev/null
+++ b/reqs/REQ001.yml
@@ -0,0 +1,42 @@
+active: true
+derived: false
+doc:
+ by: sarnold
+ copyright: tdeveloper
+ major: '1'
+ minor: A
+ name: simple
+ ref: ''
+ title: Requirements for _simple_
+header: ''
+level: 1.0
+links: []
+normative: false
+ref: ''
+reviewed: 3tp2D2vihFUgViix5tF_Ez6tAyWKm1Vd75Te-3kQ0xs=
+short-name: reqs_overview
+text: |
+ Requirements overview
+
+ The simple package is intended to provide a simple but modern example of
+ creating a project/package using setuptools/setuptools-scm with the latest
+ metadata and default build backend for PEP517 compliance.
+
+ The main dependencies are shown below.
+
+ - [importlib-metadata](https://pypi.org/project/importlib-metadata/)
+ - used for runtime version retrieval (for older Python)
+ - [munch](https://github.com/Infinidat/munch)
+ - an example convenience library for adding attribute access to dictionaries
+
+ The simple package should demonstrate the following items.
+
+ - project metadata and tool configuration in pyproject.toml
+ - project docs with auto-generated requirements, SW design, and API/interfaces
+ - getting-started setup doc and github/tox workflow automation
+ - working pre-commit configuration and REUSE license compliance
+
+ > [!IMPORTANT]
+ > The above item `short_name` is a custom doorstop attribute and
+ > must be added to the doorstop config file, as well as populated
+ > with the desired "alias" for the given item.
diff --git a/requirements.txt b/requirements.txt
index 2785064..7882975 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,2 +1,3 @@
+doorstop
importlib-resources; python_version < "3.10"
munch[yaml]
diff --git a/tests/docs/.doorstop.yml b/tests/docs/.doorstop.yml
new file mode 100644
index 0000000..0b425c2
--- /dev/null
+++ b/tests/docs/.doorstop.yml
@@ -0,0 +1,24 @@
+settings:
+ digits: 3
+ itemformat: yaml
+ parent: REQ
+ prefix: TST
+ sep: ''
+extensions:
+ item_sha_required: true # sha256
+attributes:
+ reviewed:
+ - short-name
+ defaults:
+ short-name: ''
+ doc:
+ name: simple
+ title: REQ Integration and Unit Tests
+ ref: ''
+ by: tdeveloper
+ major: '1'
+ minor: A
+ copyright: tdeveloper
+ publish:
+ - commentary
+ - rationale
diff --git a/tests/docs/TST001.yml b/tests/docs/TST001.yml
new file mode 100644
index 0000000..ed18995
--- /dev/null
+++ b/tests/docs/TST001.yml
@@ -0,0 +1,33 @@
+active: true
+derived: false
+doc:
+ by: tdeveloper
+ copyright: tdeveloper
+ major: '1'
+ minor: A
+ name: simple
+ ref: ''
+ title: REQ Integration and Unit Tests
+header: ''
+level: 1.0
+links: []
+normative: false
+ref: ''
+reviewed: qRclOuDFFHNFvLs38bcwUlNtsxegEfvbrPu7S68ZH_I=
+short-name: unit_tests
+text: |
+ Automated Tests
+
+ Whether desktop or CI, run these tests from the project root,
+ after installing Python and [Tox](https://github.com/tox-dev/tox):
+
+ ```shell
+ tox -e py
+ ```
+
+ To see test output, ie, code under test and print statements, append
+ the following positional arg to the above tox command:
+
+ ```shell
+ tox -e py -- no
+ ```
diff --git a/tox.ini b/tox.ini
index 0aad93e..22b5126 100644
--- a/tox.ini
+++ b/tox.ini
@@ -216,8 +216,17 @@ allowlist_externals =
deps =
{[base]deps}
+ {[reqs]deps}
.[doc]
+commands_pre =
+ docs: doorstop publish REQ docs/source/ds/reqs_tree.md
+ docs: doorstop publish TST docs/source/ds/unit_tests.md
+ docs: doorstop publish SDD docs/source/ds/sw_design.md
+ docs: bash docs/sphinx_prep.sh docs/source/ds/reqs_tree.md
+ docs: bash docs/sphinx_prep.sh docs/source/ds/unit_tests.md
+ docs: bash docs/sphinx_prep.sh docs/source/ds/sw_design.md
+
commands =
docs: make -C docs html
ldocs: make -C docs linkcheck
@@ -229,8 +238,6 @@ skip_install = true
description =
Run mypy type checker (needs all deps)
-setenv = PYTHONPATH = {toxinidir}/src
-
deps =
{[base]deps}
mypy
@@ -238,7 +245,7 @@ deps =
munch-stubs @ git+https://github.com/VCTLabs/munch-stubs.git@main
commands =
- python -m mypy --follow-imports=normal --install-types --non-interactive src/
+ python -m mypy --follow-imports=normal --install-types --check-untyped-defs --non-interactive src/
[testenv:reuse]
skip_install = true
@@ -281,6 +288,22 @@ deps =
commands =
bandit -c pyproject.toml -r src
+[testenv:md]
+skip_install = true
+passenv =
+ DEBUG
+ PYTHON
+ CI
+ OS
+ PYTHONIOENCODING
+ PIP_DOWNLOAD_CACHE
+
+deps =
+ {[base]deps}
+
+commands =
+ python docs/process_md_urls.py {posargs}
+
[testenv:changes]
skip_install = true
@@ -318,3 +341,4 @@ deps =
commands =
bash -c 'rm -rf src/*.egg_info dist/ build/ .coverage* coverage.xml'
bash -c 'rm -rf .pytest_cache __pycache__ src/*/__pycache__ docs/source/api'
+ bash -c 'rm -rf docs/source/ds/*.md docs/source/ds/*/*.svg'