Skip to content

Commit 09ef970

Browse files
tomschrppktscls19fr
committed
Fix #225: Deprecate module level functions
* Add test cases - Add additional test case for "check" - test_should_process_check_iscalled_with_valid_version - Test also missing finalize_version - Test the warning more thouroughly with pytest.warns instead of just pytest.deprecated_call * In `setup.cfg`, add deprecation warnings filter for pytest * Implement DeprecationWarning with warnings module and the new decorator `deprecated` * Output a DeprecationWarning for the following functions: - semver.bump_{major,minor,patch,prerelease,build} - semver.format_version - semver.finalize_version - semver.parse - semver.parse_version_info - semver.replace - semver.VersionInfo._asdict - semver.VersionInfo._astuple Add also a deprecation notice in the docstrings of these functions * Introduce new public functions: - semver.VersionInfo.to_dict (from former _asdict) - semver.VersionInfo.to_tuple (from former _astuple) - Keep _asdict and _astuple as a (deprecated) function for compatibility reasons * Update CHANGELOG.rst * Update usage documentation: - Move some information to make them more useful for for the reader - Add deprecation warning - Explain how to replace deprecated functions - Explain how to display deprecation warnings from semver * Improve documentation of deprecated functions - List deprecated module level functions - Make recommendation and show equivalent code - Mention that deprecated functions will be replaced in semver 3. That means, all deprecated function will be still available in semver 2.x.y. * Move _increment_string into VersionInfo class - Makes removing deprecating functions easier as, for example, bump_prerelease is no longer dependant from an "external" function. - Move _LAST_NUMBER regex into VersionInfo class - Implement _increment_string as a staticmethod Co-authored-by: Karol <karol@ppkt.eu> Co-authored-by: scls19fr <scls19fr@users.noreply.github.com>
1 parent 34f038d commit 09ef970

File tree

6 files changed

+549
-190
lines changed

6 files changed

+549
-190
lines changed

.gitignore

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
# Files
1+
# Patch/Diff Files
22
*.patch
33
*.diff
4-
*.kate-swp
54

65
# Byte-compiled / optimized / DLL files
76
__pycache__/
87
*.py[cod]
98
.pytest_cache/
9+
*$py.class
1010

1111
# Distribution / packaging
1212
.cache
@@ -72,3 +72,7 @@ docs/_build/
7272

7373
# PyBuilder
7474
target/
75+
76+
# Backup files
77+
*~
78+
*.kate-swp

CHANGELOG.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,24 @@ Additions
2727

2828
* :pr:`228`: Added better doctest integration
2929

30+
3031
Removals
3132
--------
33+
* :gh:`225` (:pr:`229`): Output a DeprecationWarning for the following functions:
34+
35+
- ``semver.parse``
36+
- ``semver.parse_version_info``
37+
- ``semver.format_version``
38+
- ``semver.bump_{major,minor,patch,prerelease,build}``
39+
- ``semver.finalize_version``
40+
- ``semver.replace``
41+
- ``semver.VersionInfo._asdict`` (use the new, public available
42+
function ``semver.VersionInfo.to_dict()``)
43+
- ``semver.VersionInfo._astuple`` (use the new, public available
44+
function ``semver.VersionInfo.to_tuple()``)
45+
46+
These deprecated functions will be removed in semver 3.
47+
3248

3349

3450
Version 2.9.1

docs/usage.rst

Lines changed: 205 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,10 @@ are met.
1414
Knowing the Implemented semver.org Version
1515
------------------------------------------
1616

17-
The semver.org is the authorative specification of how semantical versioning is
18-
definied. To know which version of semver.org is implemented in the semver
19-
libary, use the following constant::
17+
The semver.org page is the authorative specification of how semantical
18+
versioning is definied.
19+
To know which version of semver.org is implemented in the semver libary,
20+
use the following constant::
2021

2122
>>> semver.SEMVER_SPEC_VERSION
2223
'2.0.0'
@@ -25,35 +26,81 @@ libary, use the following constant::
2526
Creating a Version
2627
------------------
2728

28-
A version can be created in different ways:
29+
Due to historical reasons, the semver project offers two ways of
30+
creating a version:
2931

30-
* as a complete version string::
32+
* through an object oriented approach with the :class:`semver.VersionInfo`
33+
class. This is the preferred method when using semver.
34+
35+
* through module level functions and builtin datatypes (usually strings
36+
and dicts).
37+
These method are still available for compatibility reasons, but are
38+
marked as deprecated. Using one of these will emit a DeprecationWarning.
39+
40+
41+
.. warning:: **Deprecation Warning**
42+
43+
Module level functions are marked as *deprecated* in version 2.9.2 now.
44+
These functions will be removed in semver 3.
45+
For details, see the sections :ref:`sec_replace_deprecated_functions` and
46+
:ref:`sec_display_deprecation_warnings`.
47+
48+
49+
A :class:`semver.VersionInfo` instance can be created in different ways:
50+
51+
52+
* From a string::
3153

32-
>>> semver.parse_version_info("3.4.5-pre.2+build.4")
33-
VersionInfo(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4')
3454
>>> semver.VersionInfo.parse("3.4.5-pre.2+build.4")
3555
VersionInfo(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4')
3656

37-
* with individual parts::
57+
* From individual parts by a dictionary::
3858

39-
>>> semver.format_version(3, 4, 5, 'pre.2', 'build.4')
40-
'3.4.5-pre.2+build.4'
41-
>>> semver.VersionInfo(3, 5)
42-
VersionInfo(major=3, minor=5, patch=0, prerelease=None, build=None)
59+
>>> d = {'major': 3, 'minor': 4, 'patch': 5, 'prerelease': 'pre.2', 'build': 'build.4'}
60+
>>> semver.VersionInfo(**d)
61+
VersionInfo(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4')
62+
63+
As a minimum requirement, your dictionary needs at least the ``major``
64+
key, others can be omitted. You get a ``TypeError`` if your
65+
dictionary contains invalid keys.
66+
Only the keys ``major``, ``minor``, ``patch``, ``prerelease``, and ``build``
67+
are allowed.
68+
69+
* From a tuple::
70+
71+
>>> t = (3, 5, 6)
72+
>>> semver.VersionInfo(*t)
73+
VersionInfo(major=3, minor=5, patch=6, prerelease=None, build=None)
4374

4475
You can pass either an integer or a string for ``major``, ``minor``, or
4576
``patch``::
4677

47-
>>> semver.VersionInfo("3", "5")
48-
VersionInfo(major=3, minor=5, patch=0, prerelease=None, build=None)
78+
>>> semver.VersionInfo("3", "5", 6)
79+
VersionInfo(major=3, minor=5, patch=6, prerelease=None, build=None)
80+
81+
The old, deprecated module level functions are still available. If you
82+
need them, they return different builtin objects (string and dictionary).
83+
Keep in mind, once you have converted a version into a string or dictionary,
84+
it's an ordinary builtin object. It's not a special version object like
85+
the :class:`semver.VersionInfo` class anymore.
86+
87+
Depending on your use case, the following methods are available:
88+
89+
* From individual version parts into a string
90+
91+
In some cases you only need a string from your version data::
92+
93+
>>> semver.format_version(3, 4, 5, 'pre.2', 'build.4')
94+
'3.4.5-pre.2+build.4'
95+
96+
* From a string into a dictionary
4997

50-
In the simplest form, ``prerelease`` and ``build`` can also be
51-
integers::
98+
To access individual parts, you can use the function :func:`semver.parse`::
5299

53-
>>> semver.VersionInfo(1, 2, 3, 4, 5)
54-
VersionInfo(major=1, minor=2, patch=3, prerelease='4', build='5')
100+
>>> semver.parse("3.4.5-pre.2+build.4")
101+
OrderedDict([('major', 3), ('minor', 4), ('patch', 5), ('prerelease', 'pre.2'), ('build', 'build.4')])
55102

56-
If you pass an invalid version string you will get a ``ValueError``::
103+
If you pass an invalid version string you will get a ``ValueError``::
57104

58105
>>> semver.parse("1.2")
59106
Traceback (most recent call last):
@@ -172,45 +219,30 @@ If you pass invalid keys you get an exception::
172219

173220
.. _sec.convert.versions:
174221

175-
Converting Different Version Types
176-
----------------------------------
222+
Converting a VersionInfo instance into Different Types
223+
------------------------------------------------------
177224

178-
Depending which function you call, you get different types
179-
(as explained in the beginning of this chapter).
225+
Sometimes it is needed to convert a :class:`semver.VersionInfo` instance into
226+
a different type. For example, for displaying or to access all parts.
180227

181-
* From a string into :class:`semver.VersionInfo`::
182-
183-
>>> semver.VersionInfo.parse("3.4.5-pre.2+build.4")
184-
VersionInfo(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4')
228+
It is possible to convert a :class:`semver.VersionInfo` instance:
185229

186-
* From :class:`semver.VersionInfo` into a string::
230+
* Into a string with the builtin function :func:`str`::
187231

188232
>>> str(semver.VersionInfo.parse("3.4.5-pre.2+build.4"))
189233
'3.4.5-pre.2+build.4'
190234

191-
* From a dictionary into :class:`semver.VersionInfo`::
235+
* Into a dictionary with :func:`semver.VersionInfo.to_dict`::
192236

193-
>>> d = {'major': 3, 'minor': 4, 'patch': 5, 'prerelease': 'pre.2', 'build': 'build.4'}
194-
>>> semver.VersionInfo(**d)
195-
VersionInfo(major=3, minor=4, patch=5, prerelease='pre.2', build='build.4')
196-
197-
As a minimum requirement, your dictionary needs at least the ``major``
198-
key, others can be omitted. You get a ``TypeError`` if your
199-
dictionary contains invalid keys.
200-
Only ``major``, ``minor``, ``patch``, ``prerelease``, and ``build``
201-
are allowed.
202-
203-
* From a tuple into :class:`semver.VersionInfo`::
204-
205-
>>> t = (3, 5, 6)
206-
>>> semver.VersionInfo(*t)
207-
VersionInfo(major=3, minor=5, patch=6, prerelease=None, build=None)
237+
>>> v = semver.VersionInfo(major=3, minor=4, patch=5)
238+
>>> v.to_dict()
239+
OrderedDict([('major', 3), ('minor', 4), ('patch', 5), ('prerelease', None), ('build', None)])
208240

209-
* From a :class:`semver.VersionInfo` into a dictionary::
241+
* Into a tuple with :func:`semver.VersionInfo.to_tuple`::
210242

211-
>>> v = semver.VersionInfo(major=3, minor=4, patch=5)
212-
>>> semver.parse(str(v)) == {'major': 3, 'minor': 4, 'patch': 5, 'prerelease': None, 'build': None}
213-
True
243+
>>> v = semver.VersionInfo(major=5, minor=4, patch=2)
244+
>>> v.to_tuple()
245+
(5, 4, 2, None, None)
214246

215247

216248
Increasing Parts of a Version
@@ -362,8 +394,132 @@ For example:
362394

363395
.. code-block:: python
364396
365-
>>> coerce("v1.2")
397+
>>> coerce("v1.2")
366398
(VersionInfo(major=1, minor=2, patch=0, prerelease=None, build=None), '')
367399
>>> coerce("v2.5.2-bla")
368400
(VersionInfo(major=2, minor=5, patch=2, prerelease=None, build=None), '-bla')
369401
402+
403+
.. _sec_replace_deprecated_functions:
404+
405+
Replacing Deprecated Functions
406+
------------------------------
407+
408+
The development team of semver has decided to deprecate certain functions on
409+
the module level. The preferred way of using semver is through the
410+
:class:`semver.VersionInfo` class.
411+
412+
The deprecated functions can still be used in version 2.x.y. In version 3 of
413+
semver, the deprecated functions will be removed.
414+
415+
The following list shows the deprecated functions and how you can replace
416+
them with code which is compatible for future versions:
417+
418+
419+
* :func:`semver.bump_major`, :func:`semver.bump_minor`, :func:`semver.bump_patch`, :func:`semver.bump_prerelease`, :func:`semver.bump_build`
420+
421+
Replace them with the respective methods of the :class:`semver.VersionInfo`
422+
class.
423+
For example, the function :func:`semver.bump_major` is replaced by
424+
:func:`semver.VersionInfo.bump_major` and calling the ``str(versionobject)``:
425+
426+
.. code-block:: python
427+
428+
>>> s1 = semver.bump_major("3.4.5")
429+
>>> s2 = str(semver.VersionInfo.parse("3.4.5").bump_major())
430+
>>> s1 == s2
431+
True
432+
433+
Likewise with the other module level functions.
434+
435+
* :func:`semver.finalize_version`
436+
437+
Replace it with :func:`semver.VersionInfo.finalize_version`:
438+
439+
.. code-block:: python
440+
441+
>>> s1 = semver.finalize_version('1.2.3-rc.5')
442+
>>> s2 = str(semver.VersionInfo.parse('1.2.3-rc.5').finalize_version())
443+
>>> s1 == s2
444+
True
445+
446+
* :func:`semver.format_version`
447+
448+
Replace it with ``str(versionobject)``:
449+
450+
.. code-block:: python
451+
452+
>>> s1 = semver.format_version(5, 4, 3, 'pre.2', 'build.1')
453+
>>> s2 = str(semver.VersionInfo(5, 4, 3, 'pre.2', 'build.1'))
454+
>>> s1 == s2
455+
True
456+
457+
* :func:`semver.parse`
458+
459+
Replace it with :func:`semver.VersionInfo.parse` and
460+
:func:`semver.VersionInfo.to_dict`:
461+
462+
.. code-block:: python
463+
464+
>>> v1 = semver.parse("1.2.3")
465+
>>> v2 = semver.VersionInfo.parse("1.2.3").to_dict()
466+
>>> v1 == v2
467+
True
468+
469+
* :func:`semver.parse_version_info`
470+
471+
Replace it with :func:`semver.VersionInfo.parse`:
472+
473+
.. code-block:: python
474+
475+
>>> v1 = semver.parse_version_info("3.4.5")
476+
>>> v2 = semver.VersionInfo.parse("3.4.5")
477+
>>> v1 == v2
478+
True
479+
480+
* :func:`semver.replace`
481+
482+
Replace it with :func:`semver.VersionInfo.replace`:
483+
484+
.. code-block:: python
485+
486+
>>> s1 = semver.replace("1.2.3", major=2, patch=10)
487+
>>> s2 = str(semver.VersionInfo.parse('1.2.3').replace(major=2, patch=10))
488+
>>> s1 == s2
489+
True
490+
491+
492+
.. _sec_display_deprecation_warnings:
493+
494+
Displaying Deprecation Warnings
495+
-------------------------------
496+
497+
By default, deprecation warnings are `ignored in Python <https://docs.python.org/3/library/warnings.html#warning-categories>`_.
498+
This also affects semver's own warnings.
499+
500+
It is recommended that you turn on deprecation warnings in your scripts. Use one of
501+
the following methods:
502+
503+
* Use the option `-Wd <https://docs.python.org/3/using/cmdline.html#cmdoption-w>`_
504+
to enable default warnings:
505+
506+
* Directly running the Python command::
507+
508+
$ python3 -Wd scriptname.py
509+
510+
* Add the option in the shebang line (something like ``#!/usr/bin/python3``)
511+
after the command::
512+
513+
#!/usr/bin/python3 -Wd
514+
515+
* In your own scripts add a filter to ensure that *all* warnings are displayed:
516+
517+
.. code-block:: python
518+
519+
import warnings
520+
warnings.simplefilter("default")
521+
# Call your semver code
522+
523+
For further details, see the section
524+
`Overriding the default filter <https://docs.python.org/3/library/warnings.html#overriding-the-default-filter>`_
525+
of the Python documentation.

0 commit comments

Comments
 (0)