mirror of
https://github.com/drewcassidy/yaclog.git
synced 2024-09-01 14:58:58 +00:00
Add API documentation
This commit is contained in:
parent
5cc815d8b6
commit
f085f318b3
12
docs/_templates/layout.html
vendored
12
docs/_templates/layout.html
vendored
@ -1,10 +1,10 @@
|
|||||||
{% extends "!layout.html" %}
|
{% extends "!layout.html" %}
|
||||||
{% block extrahead %}
|
{% block extrahead %}
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="_static/icon-16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="/_static/icon-16.png">
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="_static/icon-32.png">
|
<link rel="icon" type="image/png" sizes="32x32" href="/_static/icon-32.png">
|
||||||
<link rel="icon" type="image/png" sizes="48x48" href="_static/icon-48.png">
|
<link rel="icon" type="image/png" sizes="48x48" href="/_static/icon-48.png">
|
||||||
<link rel="icon" type="image/png" sizes="64x64" href="_static/icon-64.png">
|
<link rel="icon" type="image/png" sizes="64x64" href="/_static/icon-64.png">
|
||||||
<link rel="icon" type="image/png" sizes="128x128" href="_static/icon-128.png">
|
<link rel="icon" type="image/png" sizes="128x128" href="/_static/icon-128.png">
|
||||||
<link rel="icon" type="image/png" sizes="256x256" href="_static/icon-256.png">
|
<link rel="icon" type="image/png" sizes="256x256" href="/_static/icon-256.png">
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
{% endblock %}
|
{% endblock %}
|
38
docs/conf.py
38
docs/conf.py
@ -4,16 +4,18 @@
|
|||||||
# list see the documentation:
|
# list see the documentation:
|
||||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||||
|
|
||||||
|
from pkg_resources import get_distribution
|
||||||
|
|
||||||
# -- Path setup --------------------------------------------------------------
|
# -- Path setup --------------------------------------------------------------
|
||||||
|
|
||||||
# If extensions (or modules to document with autodoc) are in another directory,
|
# 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
|
# 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.
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
#
|
#
|
||||||
# import os
|
import os
|
||||||
# import sys
|
import sys
|
||||||
# sys.path.insert(0, os.path.abspath('.'))
|
|
||||||
from pkg_resources import get_distribution
|
sys.path.insert(0, os.path.abspath('..'))
|
||||||
|
|
||||||
# -- Project information -----------------------------------------------------
|
# -- Project information -----------------------------------------------------
|
||||||
|
|
||||||
@ -29,7 +31,10 @@ version = '.'.join(release.split('.')[:3])
|
|||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = [
|
extensions = [
|
||||||
'myst_parser', 'sphinx_rtd_theme'
|
'myst_parser',
|
||||||
|
'sphinx_rtd_theme',
|
||||||
|
'sphinx.ext.autodoc',
|
||||||
|
'sphinx.ext.intersphinx',
|
||||||
]
|
]
|
||||||
|
|
||||||
# Add any paths that contain templates here, relative to this directory.
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
@ -40,6 +45,8 @@ templates_path = ['_templates']
|
|||||||
# This pattern also affects html_static_path and html_extra_path.
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||||
|
|
||||||
|
default_role = 'py:obj'
|
||||||
|
|
||||||
# -- Options for HTML output -------------------------------------------------
|
# -- Options for HTML output -------------------------------------------------
|
||||||
|
|
||||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
@ -54,3 +61,24 @@ html_favicon = 'favicon.ico'
|
|||||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
html_static_path = ['_static']
|
html_static_path = ['_static']
|
||||||
html_css_files = ['css/custom.css']
|
html_css_files = ['css/custom.css']
|
||||||
|
|
||||||
|
# -- Options for Autodoc -----------------------------------------------------
|
||||||
|
|
||||||
|
add_module_names = False
|
||||||
|
autodoc_docstring_signature = True
|
||||||
|
autoclass_content = 'both'
|
||||||
|
|
||||||
|
autodoc_default_options = {
|
||||||
|
'member-order': 'bysource',
|
||||||
|
'undoc-members': True,
|
||||||
|
}
|
||||||
|
|
||||||
|
# -- Options for Intersphinx -------------------------------------------------
|
||||||
|
|
||||||
|
# This config value contains the locations and names of other projects that
|
||||||
|
# should be linked to in this documentation.
|
||||||
|
|
||||||
|
intersphinx_mapping = {
|
||||||
|
'python': ('https://docs.python.org/3', None),
|
||||||
|
'packaging': ('https://packaging.pypa.io/en/latest/', None),
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@ Welcome to Yaclog's documentation!
|
|||||||
:includehidden:
|
:includehidden:
|
||||||
:caption: Contents:
|
:caption: Contents:
|
||||||
|
|
||||||
Changelog <changelog>
|
API Reference <reference/index.rst>
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
|
5
docs/reference/changelog.rst
Normal file
5
docs/reference/changelog.rst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Changelog Module
|
||||||
|
================
|
||||||
|
|
||||||
|
.. automodule:: yaclog.changelog
|
||||||
|
:members:
|
8
docs/reference/index.rst
Normal file
8
docs/reference/index.rst
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
API Reference
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:glob:
|
||||||
|
|
||||||
|
*
|
5
docs/reference/markdown.rst
Normal file
5
docs/reference/markdown.rst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Markdown Module
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. automodule:: yaclog.markdown
|
||||||
|
:members:
|
5
docs/reference/version.rst
Normal file
5
docs/reference/version.rst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
Version Module
|
||||||
|
==============
|
||||||
|
|
||||||
|
.. automodule:: yaclog.version
|
||||||
|
:members:
|
@ -1,3 +1,8 @@
|
|||||||
|
"""
|
||||||
|
Contains the `Changelog` class that represents a parsed changelog file that can be read from and written to
|
||||||
|
disk as markdown, as well as the `VersionEntry` class that represents a single version within that changelog
|
||||||
|
"""
|
||||||
|
|
||||||
# yaclog: yet another changelog tool
|
# yaclog: yet another changelog tool
|
||||||
# Copyright (c) 2021. Andrew Cassidy
|
# Copyright (c) 2021. Andrew Cassidy
|
||||||
#
|
#
|
||||||
@ -32,23 +37,21 @@ default_header = '# Changelog\n\nAll notable changes to this project will be doc
|
|||||||
class VersionEntry:
|
class VersionEntry:
|
||||||
"""Holds a single version entry in a :py:class:`Changelog`"""
|
"""Holds a single version entry in a :py:class:`Changelog`"""
|
||||||
|
|
||||||
header_regex = re.compile( # THE LANGUAGE OF THE GODS
|
_header_regex = re.compile( # THE LANGUAGE OF THE GODS
|
||||||
r"##\s+(?P<name>.*?)(?:\s+-)?(?:\s+(?P<date>\d{4}-\d{2}-\d{2}))?(?P<tags>(?:\s+\[[^]]*?])*)\s*$")
|
r"##\s+(?P<name>.*?)(?:\s+-)?(?:\s+(?P<date>\d{4}-\d{2}-\d{2}))?(?P<tags>(?:\s+\[[^]]*?])*)\s*$")
|
||||||
|
|
||||||
tag_regex = re.compile(r'\[(?P<tag>[^]]*?)]')
|
_tag_regex = re.compile(r'\[(?P<tag>[^]]*?)]')
|
||||||
|
|
||||||
def __init__(self, name: str = 'Unreleased',
|
def __init__(self, name: str = 'Unreleased',
|
||||||
date: Optional[datetime.date] = None, tags: Optional[List[str]] = None,
|
date: Optional[datetime.date] = None, tags: Optional[List[str]] = None,
|
||||||
link: Optional[str] = None, link_id: Optional[str] = None, line_no: Optional[int] = None):
|
link: Optional[str] = None, link_id: Optional[str] = None, line_no: Optional[int] = None):
|
||||||
"""
|
"""
|
||||||
Create a new version entry
|
|
||||||
|
|
||||||
:param str name: The version's name
|
:param str name: The version's name
|
||||||
:param date: When the version was released
|
:param Optional[datetime.date] date: When the version was released
|
||||||
:param tags: The version's tags
|
:param tags: The version's tags
|
||||||
:param link: The version's URL
|
:param link: The version's URL
|
||||||
:param link_id: The version's link ID
|
:param link_id: The version's link ID
|
||||||
:param line_no What line in the original file the version starts on
|
:param line_no: What line in the original file the version starts on
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self.name: str = name
|
self.name: str = name
|
||||||
@ -67,7 +70,7 @@ class VersionEntry:
|
|||||||
"""The version's link ID, uses the version name by default when writing"""
|
"""The version's link ID, uses the version name by default when writing"""
|
||||||
|
|
||||||
self.line_no: Optional[int] = line_no
|
self.line_no: Optional[int] = line_no
|
||||||
"""What line the version occurs at in the file, or None if the version was not read from a file.
|
"""What line the version occurs at in the file, or `None` if the version was not read from a file.
|
||||||
This is not guaranteed to be correct after the changelog has been modified,
|
This is not guaranteed to be correct after the changelog has been modified,
|
||||||
and it has no effect on the written file"""
|
and it has no effect on the written file"""
|
||||||
|
|
||||||
@ -86,7 +89,7 @@ class VersionEntry:
|
|||||||
"""
|
"""
|
||||||
version = cls(line_no=line_no)
|
version = cls(line_no=line_no)
|
||||||
|
|
||||||
match = cls.header_regex.match(header)
|
match = cls._header_regex.match(header)
|
||||||
assert match, f'failed to parse version header: "{header}"'
|
assert match, f'failed to parse version header: "{header}"'
|
||||||
|
|
||||||
version.name, version.link, version.link_id = markdown.strip_link(match['name'])
|
version.name, version.link, version.link_id = markdown.strip_link(match['name'])
|
||||||
@ -98,7 +101,7 @@ class VersionEntry:
|
|||||||
return cls(name=header.lstrip('#').strip(), line_no=line_no)
|
return cls(name=header.lstrip('#').strip(), line_no=line_no)
|
||||||
|
|
||||||
if match['tags']:
|
if match['tags']:
|
||||||
version.tags = [m['tag'].upper() for m in cls.tag_regex.finditer(match['tags'])]
|
version.tags = [m['tag'].upper() for m in cls._tag_regex.finditer(match['tags'])]
|
||||||
|
|
||||||
return version
|
return version
|
||||||
|
|
||||||
@ -200,11 +203,13 @@ class VersionEntry:
|
|||||||
return contents
|
return contents
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def released(self):
|
def released(self) -> bool:
|
||||||
|
"""Returns true if a PEP440 version number is present in the version name, and has no prerelease segments"""
|
||||||
return yaclog.version.is_release(self.name)
|
return yaclog.version.is_release(self.name)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def version(self):
|
def version(self):
|
||||||
|
"""Returns the PEP440 version number from the version name, or `None` if none is found"""
|
||||||
return yaclog.version.extract_version(self.name)[0]
|
return yaclog.version.extract_version(self.name)[0]
|
||||||
|
|
||||||
def __str__(self) -> str:
|
def __str__(self) -> str:
|
||||||
@ -216,7 +221,7 @@ class Changelog:
|
|||||||
|
|
||||||
def __init__(self, path=None, header: str = default_header):
|
def __init__(self, path=None, header: str = default_header):
|
||||||
"""
|
"""
|
||||||
Create a new changelog object. Contents will be automatically read from disk if the file exists
|
Contents will be automatically read from disk if the file exists
|
||||||
|
|
||||||
:param path: The changelog's path on disk
|
:param path: The changelog's path on disk
|
||||||
:param header: The header at the top of the changelog to use if the file does not exist
|
:param header: The header at the top of the changelog to use if the file does not exist
|
||||||
@ -230,7 +235,7 @@ class Changelog:
|
|||||||
self.versions: List[VersionEntry] = []
|
self.versions: List[VersionEntry] = []
|
||||||
"""A list of versions in the changelog"""
|
"""A list of versions in the changelog"""
|
||||||
|
|
||||||
self.links = {}
|
self.links: Dict[str, str] = {}
|
||||||
"""Link IDs at the end of the changelog"""
|
"""Link IDs at the end of the changelog"""
|
||||||
|
|
||||||
if path and os.path.exists(path):
|
if path and os.path.exists(path):
|
||||||
@ -339,12 +344,12 @@ class Changelog:
|
|||||||
Get the current version from the changelog
|
Get the current version from the changelog
|
||||||
|
|
||||||
:param released: if the returned version should be a released version,
|
:param released: if the returned version should be a released version,
|
||||||
an unreleased version, or ``None`` to return the most recent
|
an unreleased version, or `None` to return the most recent
|
||||||
:param new_version: if a new version should be created if none exist.
|
:param new_version: if a new version should be created if none exist.
|
||||||
:param new_version_name: The name of the version to create if there
|
:param new_version_name: The name of the version to create if there
|
||||||
are no matches and ``new_version`` is True.
|
are no matches and ``new_version`` is True.
|
||||||
:return: The current version matching the criteria,
|
:return: The current version matching the criteria,
|
||||||
or None if ``new_version`` is disabled and none are found.
|
or `None` if ``new_version`` is disabled and none are found.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# return the first version that matches `released`
|
# return the first version that matches `released`
|
||||||
@ -365,7 +370,7 @@ class Changelog:
|
|||||||
"""
|
"""
|
||||||
Get a version from the changelog
|
Get a version from the changelog
|
||||||
|
|
||||||
:param name: The name of the version to get, or ``None`` to return the most recent
|
:param name: The name of the version to get, or `None` to return the most recent
|
||||||
:return: The first version with the selected name
|
:return: The first version with the selected name
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
"""
|
||||||
|
Tools for parsing and manipulating markdown, including a very basic tokenizer.
|
||||||
|
"""
|
||||||
|
|
||||||
# yaclog: yet another changelog tool
|
# yaclog: yet another changelog tool
|
||||||
# Copyright (c) 2021. Andrew Cassidy
|
# Copyright (c) 2021. Andrew Cassidy
|
||||||
#
|
#
|
||||||
@ -13,6 +17,7 @@
|
|||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import re
|
import re
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
@ -31,23 +36,23 @@ setext_h1_replace_regex = re.compile(r'(?<=\n)(?P<header>[^\n]+?)\n=+[ \t]*(?=\n
|
|||||||
setext_h2_replace_regex = re.compile(r'(?<=\n)(?P<header>[^\n]+?)\n-+[ \t]*(?=\n)')
|
setext_h2_replace_regex = re.compile(r'(?<=\n)(?P<header>[^\n]+?)\n-+[ \t]*(?=\n)')
|
||||||
|
|
||||||
|
|
||||||
def strip_link(token):
|
def strip_link(text):
|
||||||
"""
|
"""
|
||||||
Parses and removes any links from the token
|
Parses and removes any links from the input string
|
||||||
|
|
||||||
:param token: An input token which may be a markdown link, either literal or an ID
|
:param text: An input string which may be a markdown link, either literal or an ID
|
||||||
:return: A tuple of (name, url, id)
|
:return: A tuple of (name, url, id). If the input is not a link, it is returned verbatim as the name.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if link_lit := link_lit_regex.fullmatch(token):
|
if link_lit := link_lit_regex.fullmatch(text):
|
||||||
# in the form [name](link)
|
# in the form [name](link)
|
||||||
return link_lit['text'], link_lit['link'], None
|
return link_lit['text'], link_lit['link'], None
|
||||||
|
|
||||||
if link_def := link_def_regex.fullmatch(token):
|
if link_def := link_def_regex.fullmatch(text):
|
||||||
# in the form [name][id] where id is hopefully linked somewhere else in the document
|
# in the form [name][id] where id is hopefully linked somewhere else in the document
|
||||||
return link_def['text'], None, link_def['link_id'].lower()
|
return link_def['text'], None, link_def['link_id'].lower()
|
||||||
|
|
||||||
return token, None, None
|
return text, None, None
|
||||||
|
|
||||||
|
|
||||||
def join(segments: List[str]) -> str:
|
def join(segments: List[str]) -> str:
|
||||||
@ -76,10 +81,17 @@ def join(segments: List[str]) -> str:
|
|||||||
|
|
||||||
|
|
||||||
class Token:
|
class Token:
|
||||||
|
"""A single tokenized block of markdown, consisting of one or more lines of text."""
|
||||||
|
|
||||||
def __init__(self, line_no: int, lines: List[str], kind: str):
|
def __init__(self, line_no: int, lines: List[str], kind: str):
|
||||||
self.line_no = line_no
|
self.line_no = line_no
|
||||||
|
"""Which line this block appears on in the original file"""
|
||||||
|
|
||||||
self.lines = lines
|
self.lines = lines
|
||||||
|
"""The lines of text making up this block"""
|
||||||
|
|
||||||
self.kind = kind
|
self.kind = kind
|
||||||
|
"""What kind of token this is. One of ``h[1-6]``, ``p``, ``li`` or ``code``"""
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return f'{self.kind}: {self.lines}'
|
return f'{self.kind}: {self.lines}'
|
||||||
@ -93,7 +105,7 @@ def tokenize(text: str):
|
|||||||
(Headers, top-level list items, links, code blocks, paragraphs).
|
(Headers, top-level list items, links, code blocks, paragraphs).
|
||||||
|
|
||||||
:param text: input text to tokenize
|
:param text: input text to tokenize
|
||||||
:return: A list of tokens
|
:return: A list of tokens and a dictionary of links
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# convert setext-style headers
|
# convert setext-style headers
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
"""
|
||||||
|
Various helper functions for analyzing and manipulating PEP440 version numbers,
|
||||||
|
meant to augment the `packaging.version` module.
|
||||||
|
"""
|
||||||
|
|
||||||
# yaclog: yet another changelog tool
|
# yaclog: yet another changelog tool
|
||||||
# Copyright (c) 2021. Andrew Cassidy
|
# Copyright (c) 2021. Andrew Cassidy
|
||||||
#
|
#
|
||||||
|
Loading…
Reference in New Issue
Block a user