From: <mi...@us...> - 2017-09-08 16:09:16
|
Revision: 8177 http://sourceforge.net/p/docutils/code/8177 Author: milde Date: 2017-09-08 16:09:13 +0000 (Fri, 08 Sep 2017) Log Message: ----------- Automatically update version_info when changing __version__ per script. Modified Paths: -------------- trunk/docutils/docs/dev/release.txt trunk/sandbox/infrastructure/set_version.sh Added Paths: ----------- trunk/sandbox/infrastructure/version_identifier_parsing.py Modified: trunk/docutils/docs/dev/release.txt =================================================================== --- trunk/docutils/docs/dev/release.txt 2017-09-07 20:00:57 UTC (rev 8176) +++ trunk/docutils/docs/dev/release.txt 2017-09-08 16:09:13 UTC (rev 8177) @@ -69,8 +69,8 @@ where ``<new_version>`` is major.minor[.micro][<pre>][.dev]. -Finally change ``__version_info__`` in ``docutils/docutils/__init__.py`` -**by hand** to ensure it matches the `version identifier`_. + This also changes ``__version_info__`` in + ``docutils/docutils/__init__.py``. Run the test suite after changing the codebase version to ensure accuracy and consistency. Modified: trunk/sandbox/infrastructure/set_version.sh =================================================================== --- trunk/sandbox/infrastructure/set_version.sh 2017-09-07 20:00:57 UTC (rev 8176) +++ trunk/sandbox/infrastructure/set_version.sh 2017-09-08 16:09:13 UTC (rev 8177) @@ -42,9 +42,10 @@ echo Determining list of files to be changed... # BUG ls lists directories but does not descend # (try ls --recursive) - files="docutils/__init__.py setup.py `$svn ls test/functional/expected/ | sed 's|^|test/functional/expected/|'`" - echo "Now I'll change the version number to ${new_ver} in the following files:" + files="docutils/__init__.py setup.py README.txt `$svn ls test/functional/expected/ | sed 's|^|test/functional/expected/|'`" + echo "Now I'll change the version identifier to ${new_ver} in the following files:" echo $files + echo 'and update the version_info in docutils/__init__.py.' echo echo 'Press enter to proceed (or enter anything to skip)...' read @@ -58,8 +59,9 @@ (echo ",s/$old_ver_regex/${new_ver}/g"; echo 'wq') | ed "$F" done set -e + echo 'Modifying docutils/__init__.py with version_identifier_parsing.py' + python ../sandbox/infrastructure/version_identifier_parsing.py --change-version-info=docutils/__init__.py fi - echo echo 'CAUTION: please look at the diffs carefully, for wrongly' echo ' replaced embedded numbers.' # checkin "set version number to $2" $files @@ -66,5 +68,6 @@ } set_ver "$old_ver" "$new_ver" -echo "VERIFY: major, minor, micro, releaselevel (candidate,rinal), prerelease number, pre/release or checkout" -python -c 'import docutils; print "__version_info__ =", docutils.__version_info__' + +#echo "VERIFY: major, minor, micro, releaselevel (candidate,final), prerelease serial, pre/release or checkout" +#python -c 'import docutils; print "__version_info__ =", docutils.__version_info__' Added: trunk/sandbox/infrastructure/version_identifier_parsing.py =================================================================== --- trunk/sandbox/infrastructure/version_identifier_parsing.py (rev 0) +++ trunk/sandbox/infrastructure/version_identifier_parsing.py 2017-09-08 16:09:13 UTC (rev 8177) @@ -0,0 +1,228 @@ +#!/usr/bin/env python +# version_identifier_parsing.py: parse and sort Docutils version indentifiers +# =========================================================================== + +# Parse a Docutils version identifier +# (adapted from the `PEP 440 example regexp`__) +# +# __https://www.python.org/dev/peps/pep-0440/#appendix-b-parsing-version-strings-with-regular-expressions + + +import re, argparse + +from docutils import VersionInfo, __version__, __version_info__ + + +_version_regexp = re.compile(r""" + (?P<release> + (?P<major>[0-9]+) + \.(?P<minor>[0-9]+) + (\.(?P<micro>[0-9]+))? + ) + (?P<pre> # pre-release segment + (?P<pre_l>(a|b|rc)) + (?P<pre_n>[0-9]+)? + )? + (\.(?P<dev>dev))? # dev segment + $ + """, re.VERBOSE) + +def parse_version_identifier(identifier): + """Parse a Docutils version identifier according to PEP 440.""" + return _version_regexp.match(identifier).groupdict() + + +releaselevels = {'a': 'alpha', + 'b': 'beta', + 'rc': 'candidate', + '': 'final', + } + + +def identifier2version_info(identifier): + """Convert Docutils version identifier to a `version_info` namedtuple. + """ + try: + segments = _version_regexp.match(identifier).groupdict() + except AttributeError: + raise ValueError('non-supported version identifier "%s"' % identifier) + + if segments['pre']: + releaselevel = releaselevels[segments['pre_l']] + else: + # .dev without pre-release segment sorts before pre-releases, see + # https://www.python.org/dev/peps/pep-0440/#summary-of-permitted-suffixes-and-relative-ordering + if segments['dev']: + releaselevel = None + else: + releaselevel = 'final' + + return VersionInfo( + major=int(segments['major']), + minor=int(segments['minor']), + micro=int(segments['micro']) if segments['micro'] else 0, + releaselevel=releaselevel, + serial=segments['pre_n'] and int(segments['pre_n']) or 0, + release=not segments['dev']) + + +def version_info2identifier(version_info): + """Return version identifier matching the given `docutils.version_info`.""" + release_level_abbreviations = dict((level, abbr) + for abbr, level in releaselevels.items()) + identifier = '%s.%s%s' % (version_info.major, version_info.minor, + '.%s' % version_info.micro if version_info.micro else '') + try: + identifier += release_level_abbreviations[version_info.releaselevel] + except KeyError: + if version_info.releaselevel is not None or version_info.release: + raise ValueError('releaselevel "%s" not supported. ' + 'Must be one of %s' + % (version_info.releaselevel, + ', '.join(releaselevels.values()))) + if version_info.releaselevel and version_info.serial: + identifier += str(version_info.serial) + if not version_info.release: + identifier += '.dev' + return identifier + +version_info_def_template = """\ +__version_info__ = VersionInfo( + major=%d, + minor=%d, + micro=%d, + releaselevel='%s', # one of 'alpha', 'beta', 'candidate', 'final' + # pre-release serial number (0 for final releases and active development): + serial=%d, + release=%s # True for official releases and pre-releases + ) +""" + +version_info_def_pattern = version_info_def_template.replace('%d', '[0-9]+') +version_info_def_pattern = version_info_def_pattern.replace('%s', '.*') +version_info_def_pattern = version_info_def_pattern.replace('(', r'\(') +version_info_def_pattern = version_info_def_pattern.replace(')', r'\)') + +def version_info_definition(version_identifier): + """Return __version_info__ definition code matching `version_identifier`. + """ + versioninfo = identifier2version_info(version_identifier) + return version_info_def_template % versioninfo + + +def change_version_info_definition(version, source): + """Replace the __version_info__ definition in file "source" with + a version matching the version identifer `version`.""" + version_info_def = version_info_definition(version) + sourcefile = open(source) + old = sourcefile.read() + sourcefile.close() + new = re.sub(version_info_def_pattern, version_info_def, old) + if old == new: + return "nothing to change (or parsing error)" + sourcefile = open(source, 'w') + sourcefile.write(new) + sourcefile.close() + return "changed %s" % source + + +# ----------------------------------------------------------------------- + +def test_parse(identifier): + + segments = parse_version_identifier(identifier) + print identifier + print 'release:', segments['release'] + print ' major:', segments['major'] + print ' minor:', segments['minor'] + print ' micro:', segments['micro'] + print ' pre:', segments['pre'] + print ' pre_l:', segments['pre_l'] + print ' pre_n:', segments['pre_n'] + print ' dev:', segments['dev'] + print + +def selftest(version=__version__): + """Run a test on version identification parsing and transforming.""" + + # example: series of release identifiers in version-order. + identifiers = ['0.13.1', + '0.14.dev', + '0.14a.dev', + '0.14b.dev', + '0.14b', + '0.14rc1', + '0.14rc2.dev', + '0.14rc2', + '0.14', + '0.14.1rc1.dev', + '0.14.1rc1', + '0.14.1.dev', + '0.14.1', + ] + + for identifier in identifiers: + test_parse(identifier) + + version_infos = [identifier2version_info(identifier) + for identifier in identifiers] + + for vi in version_infos: + print vi + print + + # test sort order: + + sorted_version_infos = sorted(version_infos) + + if sorted_version_infos == version_infos: + print "Version order preserved by sorting." + else: + print "Version order changed by sorting." + for vi in sorted_version_infos: + print vi + print + + # (re)convert version_info to PEP 440 version identifier: + + ids = [version_info2identifier(vi) for vi in version_infos] + + if ids == identifiers: + print "Round trip conversion OK." + else: + print ids + + + print version_info_definition(version) + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + + parser.add_argument('-i', '--version-info', + help='print version-info definition', + action='store_true') + parser.add_argument('--change-version-info', + dest='source', metavar='SOURCE', + help='change version-info def in file "source"') + parser.add_argument('-v', '--version', + help='version identifier ' + '(default docutils.__version__)') + parser.add_argument('-t', '--test', + help='test version indentification conversion', + action='store_true') + parser.add_argument('--debug', + help='print result of version identifier parsing', + action='store_true') + args = parser.parse_args() + + version_identifier = args.version or __version__ + if args.test: + selftest(version_identifier) + elif args.debug: + from pprint import pprint + pprint(_version_regexp.match(version_identifier).groupdict()) + elif args.version_info: + print version_info_definition(version_identifier) + elif args.source: + print change_version_info_definition(version_identifier, args.source) Property changes on: trunk/sandbox/infrastructure/version_identifier_parsing.py ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision \ No newline at end of property This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |