jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/409823 )
Change subject: [IMPR] Use one central point for framework version ......................................................................
[IMPR] Use one central point for framework version
Use one central point for framework version and other meta datas. Enable PEP440 versioning and also follow PEP396 when deriving version for setup.
Start with 4.0.0 as the current version which is Python 3.5+ only
- All meta data are placed within pywikibot/__metadata__.py. This enables setup.py to fetch metadata without importing pywikibot itself. - Start with 4.0.0 as the next release number. Increase the minor release number if there are other changes than just bugfixes and L10N/i18n. - Use __metadata__ in setup.py - explain submitting a new release to pypi in setup.__doc__
Bug: T106121 Bug: T171886 Bug: T197936 Bug: T253719 Change-Id: I7ffe9096fece8c15e770b5fe25d3ac29410924af --- M docs/conf.py M pywikibot/CONTENT.rst M pywikibot/__init__.py A pywikibot/__metadata__.py M setup.py M tests/utils.py 6 files changed, 140 insertions(+), 37 deletions(-)
Approvals: Zhuyifei1999: Looks good to me, approved jenkins-bot: Verified
diff --git a/docs/conf.py b/docs/conf.py index 4b42f93..3c4077b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -64,8 +64,8 @@ master_doc = 'index'
# General information about the project. -project = 'Pywikibot' -copyright = '2003-2020, Pywikibot team' +project = pywikibot.__name__.title() +copyright = pywikibot.__copyright__
# The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/pywikibot/CONTENT.rst b/pywikibot/CONTENT.rst index 883d6e3..3f606e8 100644 --- a/pywikibot/CONTENT.rst +++ b/pywikibot/CONTENT.rst @@ -7,6 +7,8 @@ | __init__.py | Initialization of the pywikibot framework, | | | basic classes and methods | +----------------------------+------------------------------------------------------+ + | __metadata__.py | pywikibot framework metadata file | + +----------------------------+------------------------------------------------------+ | _wbtypes.py | Wikibase data type classes | +----------------------------+------------------------------------------------------+ | bot.py | User-interface related functions for building bots | diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py index 8bd01df..cbd8352 100644 --- a/pywikibot/__init__.py +++ b/pywikibot/__init__.py @@ -7,9 +7,6 @@ # from __future__ import absolute_import, division, unicode_literals
-__version__ = __release__ = '4.0.dev0' -__url__ = 'https://www.mediawiki.org/wiki/Manual:Pywikibot' - import atexit import datetime from decimal import Decimal @@ -21,6 +18,12 @@
from warnings import warn
+from pywikibot.__metadata__ import ( + __copyright__, __description__, __download_url__, __license__, + __maintainer__, __maintainer_email__, __name__, __url__, __version__) + +__release__ = __version__ # backward compatibility + from pywikibot._wbtypes import WbRepresentation as _WbRepresentation from pywikibot.bot import ( input, input_choice, input_yn, inputChoice, handle_args, showHelp, ui, @@ -89,6 +92,9 @@ )
__all__ = ( + '__copyright__', '__description__', '__download_url__', '__license__', + '__maintainer__', '__maintainer_email__', '__name__', '__release__', + '__url__', '__version__', 'BadTitle', 'Bot', 'calledModuleName', 'CaptchaError', 'CascadeLockedPage', 'Category', 'CircularRedirect', 'Claim', 'config', 'CoordinateGlobeUnknownException', 'critical', 'CurrentPageBot', 'debug', diff --git a/pywikibot/__metadata__.py b/pywikibot/__metadata__.py new file mode 100644 index 0000000..468a3fb --- /dev/null +++ b/pywikibot/__metadata__.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +"""Pywikibot metadata file.""" +# +# (C) Pywikibot team, 2020 +# +# Distributed under the terms of the MIT license. +# +from __future__ import unicode_literals + +__name__ = 'pywikibot' +__version__ = '4.0.0.dev0' +__description__ = 'Python MediaWiki Bot Framework' +__maintainer__ = 'The Pywikibot team' +__maintainer_email__ = 'pywikibot@lists.wikimedia.org' +__license__ = 'MIT License' +__url__ = 'https://www.mediawiki.org/wiki/Manual:Pywikibot' +__download_url__ = 'https://tools.wmflabs.org/pywikibot/' +__copyright__ = '(C) Pywikibot team, 2003-2020' +__keywords__ = 'API bot client framework mediawiki pwb python pywiki ' \ + 'pywikibase pywikibot pywikipedia pywikipediabot wiki ' \ + 'wikibase wikidata wikimedia wikipedia' diff --git a/setup.py b/setup.py index ca96d76..fe41208 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,28 @@ # -*- coding: utf-8 -*- -"""Installer script for Pywikibot framework.""" +"""Installer script for Pywikibot framework. + +To create a new distribution: +----------------------------- + +- replace the developmental version string in ``pywikibot.__metadata.py`` + by the corresponing final release +- create the package with:: + + python setup.py sdist + +- push the change to gerrit and merge it to the repository +- upload the package to pypy by:: + + twine upload dist/* + +- create a new tag with the version number of the final release +- move the existing 'stable' tag to that new tag +- delete 'stable' tag in gerrit to be overridden later +- synchronize the local tags with the remote repositoy +- prepare the next release by increasing the version number in + ``pywikibot.__metadata.py`` and adding developmental identifier +- upload this patchset to gerrit and merge it. +""" # # (C) Pywikibot team, 2009-2020 # @@ -8,6 +31,7 @@ import os import sys
+from pkg_resources import parse_version, safe_version from setuptools import setup
PYTHON_VERSION = sys.version_info[:3] @@ -117,32 +141,80 @@ test_deps += ['six']
-def get_version(name): - """Get a valid pywikibot module version string. +class _DottedDict(dict): + __getattr__ = dict.__getitem__
- Either create a timebased version number for the package - or read the version number from the package. + +# import metadata +metadata = _DottedDict() +name = 'pywikibot' +path = os.path.abspath(os.path.dirname(__file__)) +with open(os.path.join(path, name, '__metadata__.py')) as f: + exec(f.read(), metadata) +assert metadata.__name__ == name + + +def get_validated_version(): + """Get a validated pywikibot module version string. + + The version number from pywikibot.__metadata__.__version__ is used. + setup.py with 'sdist' option is used to create a new source distribution. + In that case the version number is validated: Read tags from git. + Verify that the new release is higher than the last repository tag + and is not a developmental release.
@return: pywikibot module version string @rtype: str """ - version = '4.0' + version = metadata.__version__ + if 'sdist' not in sys.argv: + return version + + if PY2: + raise RuntimeError( + 'A new distribution cannot be created with Python {}' + .format(sys.version.split(None, 1)[0])) + + # validate version for sdist + from contextlib import suppress + from subprocess import run, PIPE try: - import subprocess - date = subprocess.check_output( - ['git', 'log', '-1', '--format=%ci']).strip() - date = date.decode().split(' ', 1)[0].replace('-', '') - version += '.' + date - if 'sdist' not in sys.argv: - version += '.dev0' + tags = run(['git', 'tag'], check=True, stdout=PIPE, + universal_newlines=True).stdout.splitlines() except Exception as e: print(e) - from pkg_resources import get_distribution, DistributionNotFound - try: - version = get_distribution(name).version - except DistributionNotFound as e: - print(e) - version += '.dev0' + sys.exit('Creating source distribution canceled.') + + for tag in ('stable', 'python2'): + with suppress(ValueError): + tags.remove(tag) + + last_tag = tags[-1] + + warnings = [] + if 'dev' in version: + warnings.append('Distribution must not be a developmental release.') + + if parse_version(version) < parse_version('0'): + # any version which is not a valid PEP 440 version will be considered + # less than any valid PEP 440 version + warnings.append( + version + ' is not a valid version string following PEP 440.') + elif safe_version(version) != version: + warnings.append( + '{} does not follow PEP 440. Use {} as version string instead.' + .format(version, safe_version(version))) + + if parse_version(version) <= parse_version(last_tag): + warnings.append( + 'New version "{}" is not higher than last version "{}".' + .format(version, last_tag)) + + if warnings: + print(__doc__) + print('\n\n'.join(warnings)) + sys.exit('\nBuild of distribution package canceled.') + return version
@@ -176,24 +248,22 @@
def main(): """Setup entry point.""" - name = 'pywikibot' + version = get_validated_version() setup( - name=name, - version=get_version(name), - description='Python MediaWiki Bot Framework', + name=metadata.__name__, + version=version, + description=metadata.__description__, long_description=read_desc('README.rst'), - keywords=['API', 'bot', 'framework', 'mediawiki', 'pwb', 'python', - 'pywikibot', 'pywikipedia', 'pywikipediabot', 'wiki', - 'wikimedia', 'wikipedia'], - maintainer='The Pywikibot team', - maintainer_email='pywikibot@lists.wikimedia.org', - license='MIT License', + keywords=metadata.__keywords__.split(), + maintainer=metadata.__maintainer__, + maintainer_email=metadata.__maintainer_email__, + license=metadata.__license__, packages=get_packages(name), python_requires='>=3.5.0', install_requires=dependencies, extras_require=extra_deps, - url='https://www.mediawiki.org/wiki/Manual:Pywikibot', - download_url='https://tools.wmflabs.org/pywikibot/', + url=metadata.__url__, + download_url=metadata.__download_url__, test_suite='tests.collector', tests_require=test_deps, classifiers=[ @@ -217,6 +287,10 @@ use_2to3=False )
+ # Finally show distribution version before uploading + if 'sdist' in sys.argv: + print('\nDistribution package created for version {}'.format(version)) +
if __name__ == '__main__': main() diff --git a/tests/utils.py b/tests/utils.py index 8571d6c..8686e90 100644 --- a/tests/utils.py +++ b/tests/utils.py @@ -601,7 +601,7 @@ @type command: list of unicode """ if PY2 or PYTHON_VERSION < (3, 5, 0): - command.insert(1, '-W ignore::FutureWarning:pywikibot:125') + command.insert(1, '-W ignore::FutureWarning:pywikibot:131') if cryptography_version and cryptography_version < [1, 3, 4]: command.insert(1, '-W ignore:Old version of cryptography:Warning') # Any environment variables added on Windows must be of type