Skip to content

Commit 158f19f

Browse files
authored
Merge pull request #228 from tomschr/feature/integrate-doctests
Add better doctest integration into pytest
2 parents 6878916 + 6669ba0 commit 158f19f

File tree

7 files changed

+80
-64
lines changed

7 files changed

+80
-64
lines changed

CHANGELOG.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,15 @@ Features
1818
Bug Fixes
1919
---------
2020

21-
* :gh:`224` (:pr:`226`): Replaced in class ``clean``, ``super(CleanCommand, self).run()`` with
22-
``CleanCommand.run(self)``
21+
* :gh:`224` (:pr:`226`): In ``setup.py``, replaced in class ``clean``,
22+
``super(CleanCommand, self).run()`` with ``CleanCommand.run(self)``
2323

2424

25+
Additions
26+
---------
27+
28+
* :pr:`228`: Added better doctest integration
29+
2530
Removals
2631
--------
2732

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ different parts, use the `semver.parse` function:
6868
>>> ver['prerelease']
6969
'pre.2'
7070
>>> ver['build']
71-
'build.5'
71+
'build.4'
7272
7373
To raise parts of a version, there are a couple of functions available for
7474
you. The `semver.parse_version_info` function converts a version string
@@ -87,7 +87,7 @@ It is allowed to concatenate different "bump functions":
8787
.. code-block:: python
8888
8989
>>> ver.bump_major().bump_minor()
90-
VersionInfo(major=4, minor=0, patch=1, prerelease=None, build=None)
90+
VersionInfo(major=4, minor=1, patch=0, prerelease=None, build=None)
9191
9292
To compare two versions, semver provides the `semver.compare` function.
9393
The return value indicates the relationship between the first and second

conftest.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,13 @@
11
import pytest
22
import semver
3+
import sys
4+
5+
sys.path.insert(0, "docs")
6+
7+
from coerce import coerce # noqa:E402
38

49

510
@pytest.fixture(autouse=True)
611
def add_semver(doctest_namespace):
712
doctest_namespace["semver"] = semver
13+
doctest_namespace["coerce"] = coerce

docs/coerce.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import re
2+
import semver
3+
4+
BASEVERSION = re.compile(
5+
r"""[vV]?
6+
(?P<major>0|[1-9]\d*)
7+
(\.
8+
(?P<minor>0|[1-9]\d*)
9+
(\.
10+
(?P<patch>0|[1-9]\d*)
11+
)?
12+
)?
13+
""",
14+
re.VERBOSE,
15+
)
16+
17+
18+
def coerce(version):
19+
"""
20+
Convert an incomplete version string into a semver-compatible VersionInfo
21+
object
22+
23+
* Tries to detect a "basic" version string (``major.minor.patch``).
24+
* If not enough components can be found, missing components are
25+
set to zero to obtain a valid semver version.
26+
27+
:param str version: the version string to convert
28+
:return: a tuple with a :class:`VersionInfo` instance (or ``None``
29+
if it's not a version) and the rest of the string which doesn't
30+
belong to a basic version.
31+
:rtype: tuple(:class:`VersionInfo` | None, str)
32+
"""
33+
match = BASEVERSION.search(version)
34+
if not match:
35+
return (None, version)
36+
37+
ver = {
38+
key: 0 if value is None else value for key, value in match.groupdict().items()
39+
}
40+
ver = semver.VersionInfo(**ver)
41+
rest = match.string[match.end() :] # noqa:E203
42+
return ver, rest

docs/development.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,7 @@ documentation includes:
174174
1
175175
>>> semver.compare("2.0.0", "2.0.0")
176176
0
177+
177178
"""
178179

179180
* **The documentation**

docs/usage.rst

Lines changed: 19 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ A version can be created in different ways:
5151
integers::
5252

5353
>>> semver.VersionInfo(1, 2, 3, 4, 5)
54-
VersionInfo(major=1, minor=2, patch=3, prerelease=4, build=5)
54+
VersionInfo(major=1, minor=2, patch=3, prerelease='4', build='5')
5555

5656
If you pass an invalid version string you will get a ``ValueError``::
5757

5858
>>> semver.parse("1.2")
59-
Traceback (most recent call last)
59+
Traceback (most recent call last):
6060
...
6161
ValueError: 1.2 is not valid SemVer string
6262

@@ -80,8 +80,8 @@ Parsing a Version String
8080

8181
* With :func:`semver.parse`::
8282

83-
>>> semver.parse("3.4.5-pre.2+build.4")
84-
{'major': 3, 'minor': 4, 'patch': 5, 'prerelease': 'pre.2', 'build': 'build.4'}
83+
>>> semver.parse("3.4.5-pre.2+build.4") == {'major': 3, 'minor': 4, 'patch': 5, 'prerelease': 'pre.2', 'build': 'build.4'}
84+
True
8585

8686

8787
Checking for a Valid Semver Version
@@ -92,9 +92,9 @@ classmethod :func:`semver.VersionInfo.isvalid`:
9292

9393
.. code-block:: python
9494
95-
>>> VersionInfo.isvalid("1.0.0")
95+
>>> semver.VersionInfo.isvalid("1.0.0")
9696
True
97-
>>> VersionInfo.isvalid("invalid")
97+
>>> semver.VersionInfo.isvalid("invalid")
9898
False
9999
100100
@@ -106,7 +106,7 @@ parts of a version:
106106

107107
.. code-block:: python
108108
109-
>>> v = VersionInfo.parse("3.4.5-pre.2+build.4")
109+
>>> v = semver.VersionInfo.parse("3.4.5-pre.2+build.4")
110110
>>> v.major
111111
3
112112
>>> v.minor
@@ -122,20 +122,20 @@ However, the attributes are read-only. You cannot change an attribute.
122122
If you do, you get an ``AttributeError``::
123123

124124
>>> v.minor = 5
125-
Traceback (most recent call last)
125+
Traceback (most recent call last):
126126
...
127127
AttributeError: attribute 'minor' is readonly
128128

129129
In case you need the different parts of a version stepwise, iterate over the :class:`semver.VersionInfo` instance::
130130

131-
>>> for item in VersionInfo.parse("3.4.5-pre.2+build.4"):
131+
>>> for item in semver.VersionInfo.parse("3.4.5-pre.2+build.4"):
132132
... print(item)
133133
3
134134
4
135135
5
136136
pre.2
137137
build.4
138-
>>> list(VersionInfo.parse("3.4.5-pre.2+build.4"))
138+
>>> list(semver.VersionInfo.parse("3.4.5-pre.2+build.4"))
139139
[3, 4, 5, 'pre.2', 'build.4']
140140

141141

@@ -160,12 +160,12 @@ unmodified, use one of the functions :func:`semver.replace` or
160160
If you pass invalid keys you get an exception::
161161

162162
>>> semver.replace("1.2.3", invalidkey=2)
163-
Traceback (most recent call last)
163+
Traceback (most recent call last):
164164
...
165165
TypeError: replace() got 1 unexpected keyword argument(s): invalidkey
166166
>>> version = semver.VersionInfo.parse("1.4.5-pre.1+build.6")
167167
>>> version.replace(invalidkey=2)
168-
Traceback (most recent call last)
168+
Traceback (most recent call last):
169169
...
170170
TypeError: replace() got 1 unexpected keyword argument(s): invalidkey
171171

@@ -209,8 +209,8 @@ Depending which function you call, you get different types
209209
* From a :class:`semver.VersionInfo` into a dictionary::
210210

211211
>>> v = semver.VersionInfo(major=3, minor=4, patch=5)
212-
>>> semver.parse(str(v))
213-
{'major': 3, 'minor': 4, 'patch': 5, 'prerelease': None, 'build': None}
212+
>>> semver.parse(str(v)) == {'major': 3, 'minor': 4, 'patch': 5, 'prerelease': None, 'build': None}
213+
True
214214

215215

216216
Increasing Parts of a Version
@@ -267,8 +267,8 @@ To compare two versions depends on your type:
267267
Use the specific operator. Currently, the operators ``<``,
268268
``<=``, ``>``, ``>=``, ``==``, and ``!=`` are supported::
269269

270-
>>> v1 = VersionInfo.parse("3.4.5")
271-
>>> v2 = VersionInfo.parse("3.5.1")
270+
>>> v1 = semver.VersionInfo.parse("3.4.5")
271+
>>> v2 = semver.VersionInfo.parse("3.5.1")
272272
>>> v1 < v2
273273
True
274274
>>> v1 > v2
@@ -278,7 +278,7 @@ To compare two versions depends on your type:
278278

279279
Use the operator as with two :class:`semver.VersionInfo` types::
280280

281-
>>> v = VersionInfo.parse("3.4.5")
281+
>>> v = semver.VersionInfo.parse("3.4.5")
282282
>>> v > (1, 0)
283283
True
284284
>>> v < (3, 5)
@@ -350,48 +350,9 @@ However, "basic" version strings consisting of major, minor,
350350
and patch part, can be easy to convert. The following function extract this
351351
information and returns a tuple with two items:
352352

353-
.. code-block:: python
353+
.. literalinclude:: coerce.py
354+
:language: python
354355

355-
import re
356-
357-
BASEVERSION = re.compile(
358-
r"""[vV]?
359-
(?P<major>0|[1-9]\d*)
360-
(\.
361-
(?P<minor>0|[1-9]\d*)
362-
(\.
363-
(?P<patch>0|[1-9]\d*)
364-
)?
365-
)?
366-
""",
367-
re.VERBOSE,
368-
)
369-
def coerce(version):
370-
"""
371-
Convert an incomplete version string into a semver-compatible VersionInfo
372-
object
373-
374-
* Tries to detect a "basic" version string (``major.minor.patch``).
375-
* If not enough components can be found, missing components are
376-
set to zero to obtain a valid semver version.
377-
378-
:param str version: the version string to convert
379-
:return: a tuple with a :class:`VersionInfo` instance (or ``None``
380-
if it's not a version) and the rest of the string which doesn't
381-
belong to a basic version.
382-
:rtype: tuple(:class:`VersionInfo` | None, str)
383-
"""
384-
match = BASEVERSION.search(version)
385-
if not match:
386-
return (None, version)
387-
388-
ver = {
389-
key: 0 if value is None else value
390-
for key, value in match.groupdict().items()
391-
}
392-
ver = semver.VersionInfo(**ver)
393-
rest = match.string[match.end() :]
394-
return ver, rest
395356

396357
The function returns a *tuple*, containing a :class:`VersionInfo`
397358
instance or None as the first element and the rest as the second element.

setup.cfg

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
[tool:pytest]
22
norecursedirs = .git build .env/ env/ .pyenv/ .tmp/ .eggs/
3+
testpaths = . docs
34
addopts =
4-
--ignore=.eggs/
55
--no-cov-on-fail
66
--cov=semver
77
--cov-report=term-missing
8+
--doctest-glob='*.rst'
89
--doctest-modules
910
--doctest-report ndiff
1011

@@ -17,4 +18,4 @@ exclude =
1718
.git,
1819
__pycache__,
1920
build,
20-
dist
21+
dist

0 commit comments

Comments
 (0)