Skip to content

Commit 7d00884

Browse files
committed
Improve API documentation
* Use sphinx-apidoc to build API documentation * Amend tox.ini and call sphinx-apidoc * Remove old autosummary; it turned out it was difficult to configure and returned warning messages which were hard to fix. * Add semver version in footer * Add semver.__about__ to API doc * Unorthodox solution with sed * Remove obsolete config variables in docs/config.py * Add docs/_api/semver.__about__.rst as a placeholder * Add changelog.d/304.doc.rst (An old attempt was to use autosummary from https://stackoverflow.com/a/62613202; however, that didn't work quite well.) Co-authored-by: Tom Schraitle <[email protected]>
1 parent bb2cb90 commit 7d00884

18 files changed

+178
-23
lines changed

Diff for: .gitignore

+2-1
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,8 @@ fabric.properties
259259
# --------
260260

261261

262-
263262
# Patch/Diff Files
264263
*.patch
265264
*.diff
265+
docs/_api
266+
!docs/_api/semver.__about__.rst

Diff for: changelog.d/304.doc.rst

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Several improvements in documentation:
2+
3+
* Reorganize API documentation.
4+
* Add migration chapter from semver2 to semver3.
5+
* Distinguish between changlog for version 2 and 3

Diff for: docs/_api/semver.__about__.rst

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
semver.\_\_about\_\_ module
2+
===========================
3+
4+
.. automodule:: semver.__about__
5+
:members:

Diff for: docs/_static/css/custom.css

+5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ div.related.top nav {
2626
margin-top: 0.5em;
2727
}
2828

29+
.sphinxsidebarwrapper .caption {
30+
margin-top: 1em;
31+
margin-bottom: -0.75em;
32+
}
33+
2934
.section h1 {
3035
font-weight: 700;
3136
}

Diff for: docs/_templates/layout.html

+45
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,48 @@
22
Import the theme's layout.
33
#}
44
{% extends "!layout.html" %}
5+
6+
{%- block footer %}
7+
<div class="footer">
8+
<p>
9+
{% if show_copyright %}&copy;{{ copyright }}.{% endif %}
10+
{% if theme_show_powered_by|lower == 'true' %}
11+
{% if show_copyright %}|{% endif %}
12+
{% if show_copyright %}|{% endif %}
13+
Powered by <a href="http://sphinx-doc.org/">Sphinx {{ sphinx_version }}</a>
14+
&amp; <a href="https://github.com/bitprophet/alabaster">Alabaster {{ alabaster_version }}</a>
15+
{% endif %}
16+
{%- if show_source and has_source and sourcename %}
17+
{% if show_copyright or theme_show_powered_by %}|{% endif %}
18+
<a href="{{ pathto('_sources/' + sourcename, true)|e }}"
19+
rel="nofollow">{{ _('Page source') }}</a>
20+
{%- endif %}
21+
</p>
22+
<p>
23+
For <a href="https://github.com/{{ theme_github_user }}/{{ theme_github_repo }}"
24+
>semver {{ version }}</a>
25+
</p>
26+
</div>
27+
28+
{% if theme_github_banner|lower != 'false' %}
29+
<a href="https://github.com/{{ theme_github_user }}/{{ theme_github_repo }}" class="github">
30+
<img style="position: absolute; top: 0; right: 0; border: 0;" src="{{ pathto('_static/' ~ theme_github_banner, 1) if theme_github_banner|lower != 'true' else 'https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png' }}" alt="Fork me on GitHub" class="github"/>
31+
</a>
32+
{% endif %}
33+
{% if theme_analytics_id %}
34+
<script type="text/javascript">
35+
36+
var _gaq = _gaq || [];
37+
_gaq.push(['_setAccount', '{{ theme_analytics_id }}']);
38+
_gaq.push(['_setDomainName', 'none']);
39+
_gaq.push(['_setAllowLinker', true]);
40+
_gaq.push(['_trackPageview']);
41+
42+
(function() {
43+
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
44+
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
45+
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
46+
})();
47+
</script>
48+
{% endif %}
49+
{%- endblock %}

Diff for: docs/api.rst

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
.. _api:
22

3+
###
34
API
4-
===
5+
###
56

6-
.. automodule:: semver
7-
:members:
8-
:undoc-members:
7+
.. toctree::
8+
:maxdepth: 4
9+
10+
_api/semver

Diff for: docs/coerce.py

+5-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import re
2-
import semver
2+
from semver import Version
3+
from typing import Optional, Tuple
4+
35

46
BASEVERSION = re.compile(
57
r"""[vV]?
@@ -15,7 +17,7 @@
1517
)
1618

1719

18-
def coerce(version):
20+
def coerce(version: str) -> Tuple[Version, Optional[str]]:
1921
"""
2022
Convert an incomplete version string into a semver-compatible Version
2123
object
@@ -37,6 +39,6 @@ def coerce(version):
3739
ver = {
3840
key: 0 if value is None else value for key, value in match.groupdict().items()
3941
}
40-
ver = semver.Version(**ver)
42+
ver = Version(**ver)
4143
rest = match.string[match.end() :] # noqa:E203
4244
return ver, rest

Diff for: docs/conf.py

+32-5
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,35 @@
1616
# add these directories to sys.path here. If the directory is relative to the
1717
# documentation root, use os.path.abspath to make it absolute, like shown here.
1818
#
19+
import codecs
1920
import os
21+
import re
2022
import sys
2123

2224
sys.path.insert(0, os.path.abspath("../src/"))
25+
# from semver import __version__ # noqa: E402
2326

24-
from semver import __version__ # noqa: E402
27+
28+
def read(*parts):
29+
"""
30+
Build an absolute path from *parts* and and return the contents of the
31+
resulting file. Assume UTF-8 encoding.
32+
"""
33+
here = os.path.abspath(os.path.dirname(__file__))
34+
with codecs.open(os.path.join(here, *parts), "rb", "utf-8") as f:
35+
return f.read()
36+
37+
38+
def find_version(*file_paths):
39+
"""
40+
Build a path from *file_paths* and search for a ``__version__``
41+
string inside.
42+
"""
43+
version_file = read(*file_paths)
44+
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", version_file, re.M)
45+
if version_match:
46+
return version_match.group(1)
47+
raise RuntimeError("Unable to find version string.")
2548

2649

2750
# -- General configuration ------------------------------------------------
@@ -35,12 +58,16 @@
3558
# ones.
3659
extensions = [
3760
"sphinx.ext.autodoc",
61+
"sphinx.ext.autosummary",
3862
"sphinx_autodoc_typehints",
3963
"sphinx.ext.intersphinx",
40-
"sphinx.ext.napoleon",
4164
"sphinx.ext.extlinks",
4265
]
4366

67+
autoclass_content = "class"
68+
autodoc_default_options = {}
69+
70+
4471
# Add any paths that contain templates here, relative to this directory.
4572
templates_path = ["_templates"]
4673

@@ -62,16 +89,16 @@
6289
# built documents.
6390
#
6491
# The short X.Y version.
65-
version = __version__
92+
release = find_version("../src/semver/__about__.py")
6693
# The full version, including alpha/beta/rc tags.
67-
release = version
94+
version = release # .rsplit(u".", 1)[0]
6895

6996
# The language for content autogenerated by Sphinx. Refer to documentation
7097
# for a list of supported languages.
7198
#
7299
# This is also used if you do content translation via gettext catalogs.
73100
# Usually you set "language" from the command line for these cases.
74-
language = None
101+
language = "en"
75102

76103
# List of patterns, relative to source directory, that match files and
77104
# directories to ignore when looking for source files.

Diff for: docs/readme.rst

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
.. include:: ../README.rst
1+
If you are searching for how to stay compatible
2+
with semver3, refer to :ref:`semver2-to-3`.
23

4+
.. include:: ../README.rst

Diff for: docs/usage.rst

+1-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ A :class:`semver.Version` instance can be created in different ways:
8989
ValueError: 'major' is negative. A version can only be positive.
9090

9191
As a minimum requirement, your dictionary needs at least the
92-
be positive.
92+
be positive.
9393

9494
>>> semver.Version(-1)
9595
Traceback (most recent call last):

Diff for: src/semver/__about__.py

+21
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,29 @@
1+
"""
2+
Metadata about semver.
3+
4+
Contains information about semver's version, the implemented version
5+
of the semver specifictation, author, maintainers, and description.
6+
7+
.. autodata:: __version__
8+
"""
9+
10+
#: Semver version
111
__version__ = "3.0.0-dev.2"
12+
13+
#: Original semver author
214
__author__ = "Kostiantyn Rybnikov"
15+
16+
#: Author's email address
317
__author_email__ = "[email protected]"
18+
19+
#: Current maintainer
420
__maintainer__ = ["Sebastien Celles", "Tom Schraitle"]
21+
22+
#: Maintainer's email address
523
__maintainer_email__ = "[email protected]"
24+
25+
#: Short description about semver
626
__description__ = "Python helper for Semantic Versioning (http://semver.org)"
727

28+
#: Supported semver specification
829
SEMVER_SPEC_VERSION = "2.0.0"

Diff for: src/semver/__init__.py

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
"""
2+
semver package major release 3.
3+
4+
A Python module for semantic versioning. Simplifies comparing versions.
5+
"""
6+
17
from ._deprecated import (
28
bump_build,
39
bump_major,

Diff for: src/semver/__main__.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
"""
22
Module to support call with :file:`__main__.py`. Used to support the following
3-
call:
3+
call::
4+
5+
$ python3 -m semver ...
6+
7+
This makes it also possible to "run" a wheel like in this command::
8+
9+
$ python3 semver-3*-py3-none-any.whl/semver -h
410
5-
$ python3 -m semver ...
611
"""
712
import os.path
813
import sys

Diff for: src/semver/_deprecated.py

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
"""
2+
Contains all deprecated functions.
3+
4+
.. autofunction: deprecated
5+
"""
16
import inspect
27
import warnings
38
from functools import partial, wraps
@@ -102,8 +107,10 @@ def parse_version_info(version):
102107
Use :func:`semver.VersionInfo.parse` instead.
103108
.. versionadded:: 2.7.2
104109
Added :func:`semver.parse_version_info`
110+
105111
:param version: version string
106112
:return: a :class:`VersionInfo` instance
113+
107114
>>> version_info = semver.Version.parse("3.4.5-pre.2+build.4")
108115
>>> version_info.major
109116
3
@@ -356,11 +363,13 @@ def replace(version, **parts):
356363
Use :func:`semver.Version.replace` instead.
357364
.. versionadded:: 2.9.0
358365
Added :func:`replace`
366+
359367
:param version: the version string to replace
360368
:param parts: the parts to be updated. Valid keys are:
361369
``major``, ``minor``, ``patch``, ``prerelease``, or ``build``
362370
:return: the replaced version string
363371
:raises TypeError: if ``parts`` contains invalid keys
372+
364373
>>> import semver
365374
>>> semver.replace("1.2.3", major=2, patch=10)
366375
'2.2.10'

Diff for: src/semver/cli.py

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""CLI parsing for :command:`pysemver` command."""
2+
13
import argparse
24
import sys
35
from typing import cast, List

Diff for: src/semver/version.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Version handling."""
2+
13
import collections
24
import re
35
from functools import wraps
@@ -414,7 +416,7 @@ def next_version(self, part: str, prerelease_token: str = "rc") -> "Version":
414416
The "major", "minor", and "patch" raises the respective parts like
415417
the ``bump_*`` functions. The real difference is using the
416418
"preprelease" part. It gives you the next patch version of the
417-
prerelease, for example:
419+
prerelease, for example:
418420
419421
>>> str(semver.parse("0.1.4").next_version("prerelease"))
420422
'0.1.5-rc.1'
@@ -550,6 +552,7 @@ def match(self, match_expr: str) -> bool:
550552
== equal
551553
!= not equal
552554
:return: True if the expression matches the version, otherwise False
555+
553556
>>> semver.Version.parse("2.0.0").match(">=1.0.0")
554557
True
555558
>>> semver.Version.parse("1.0.0").match(">1.0.0")
@@ -591,9 +594,11 @@ def parse(cls, version: String) -> "Version":
591594
.. versionchanged:: 2.11.0
592595
Changed method from static to classmethod to
593596
allow subclasses.
597+
594598
:param version: version string
595599
:return: a :class:`VersionInfo` instance
596600
:raises ValueError: if version is invalid
601+
597602
>>> semver.Version.parse('3.4.5-pre.2+build.4')
598603
VersionInfo(major=3, minor=4, patch=5, \
599604
prerelease='pre.2', build='build.4')
@@ -651,5 +656,5 @@ def isvalid(cls, version: str) -> bool:
651656
return False
652657

653658

654-
# Keep the VersionInfo name for compatibility
659+
#: Keep the VersionInfo name for compatibility
655660
VersionInfo = Version

Diff for: tests/conftest.py

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
@pytest.fixture(autouse=True)
1414
def add_semver(doctest_namespace):
15+
doctest_namespace["Version"] = semver.Version
1516
doctest_namespace["semver"] = semver
1617
doctest_namespace["coerce"] = coerce
1718
doctest_namespace["SemVerWithVPrefix"] = SemVerWithVPrefix

0 commit comments

Comments
 (0)