jenkins-bot submitted this change.

View Change

Approvals: Xqt: Looks good to me, approved jenkins-bot: Verified
[FIX] Enable site-package installation from git repository (Part 2)

- Check the Python version in pwb.py caller script and remove this
check from setup.py because site-package has its own validation.
- give up Python 2.7 compatibility of the wrapper.py script.
use pathlib to extract the root direcories. Also remove exception
handling which is no longer needed.
- update make_dist.py
- add pwb to documentation

Bug: T320851
Change-Id: Id9d7344e740bb848a4b0972d4f3b2362634dc1ba
---
D call_pwb.py
M docs/utilities/install.rst
M make_dist.py
A pwb.py
M pywikibot/scripts/wrapper.py
M setup.py
6 files changed, 186 insertions(+), 160 deletions(-)

diff --git a/call_pwb.py b/call_pwb.py
deleted file mode 100644
index a5d7764..0000000
--- a/call_pwb.py
+++ /dev/null
@@ -1,15 +0,0 @@
-"""pwb caller script to invoke the :mod:`pywikibot.scripts.wrapper` script.
-
-.. versionadded:: 8.0
-"""
-#
-# (C) Pywikibot team, 2022
-#
-# Distributed under the terms of the MIT license.
-#
-import sys
-
-from pywikibot.scripts.wrapper import main
-
-if __name__ == '__main__':
- sys.exit(main())
diff --git a/docs/utilities/install.rst b/docs/utilities/install.rst
index 475109e..dbf4134 100644
--- a/docs/utilities/install.rst
+++ b/docs/utilities/install.rst
@@ -10,3 +10,8 @@
------------

.. automodule:: setup
+
+entry point
+-----------
+
+.. automodule:: pwb
diff --git a/make_dist.py b/make_dist.py
index e91cd40..053ddae 100644
--- a/make_dist.py
+++ b/make_dist.py
@@ -3,21 +3,21 @@

The following options are supported:

--help Print documentation of this file and of setup.py
+-help Print documentation of this file and of setup.py

--local Install the distribution as a local site-package. If a
- Pywikibot package is already there, it will be uninstalled
- first.
+-local Install the distribution as a local site-package. If a
+ Pywikibot package is already there, it will be uninstalled
+ first.

--remote Upload the package to pypi. This cannot be done if the
- Pywikibot version is a development release.
+-remote Upload the package to pypi. This cannot be done if the
+ Pywikibot version is a development release.

--clear Clear old dist folders
+-clear Clear old dist folders

--upgrade Upgrade distribution packages pip, setuptools, wheel and twine
- first
+-upgrade Upgrade distribution packages pip, setuptools, wheel and twine
+ first

--nodist Do not create a distribution. Useful to -clear or -upgrade only.
+-nodist Do not create a distribution. Useful to -clear or -upgrade only.

Usage::

@@ -41,6 +41,7 @@
#
# Distributed under the terms of the MIT license.
#
+import abc
import shutil
import sys
from subprocess import check_call
@@ -51,56 +52,111 @@
import setup


-def clear_old_dist() -> None: # pragma: no cover
- """Delete old dist folders.
+class SetupBase(abc.ABC):

- .. versionadded:: 7.5
+ """Setup distribution base class.
+
+ .. versionadded:: 8.0
"""
- info('Removing old dist folders... ', newline=False)
- folder = Path().resolve()
- shutil.rmtree(folder / 'build', ignore_errors=True)
- shutil.rmtree(folder / 'dist', ignore_errors=True)
- shutil.rmtree(folder / 'pywikibot.egg-info', ignore_errors=True)
- info('done')
+
+ def __init__(self, local, remote, clear, upgrade, nodist) -> None:
+ """Initializer."""
+ self.local = local
+ self.remote = remote
+ self.clear = clear
+ self.upgrade = upgrade
+ self.nodist = nodist
+ self.folder = Path().resolve()
+
+ def clear_old_dist(self) -> None:
+ """Delete old dist folders.
+
+ .. versionadded:: 7.5
+ """
+ info('Removing old dist folders... ', newline=False)
+ shutil.rmtree(self.folder / 'build', ignore_errors=True)
+ shutil.rmtree(self.folder / 'dist', ignore_errors=True)
+ shutil.rmtree(self.folder / 'pywikibot.egg-info', ignore_errors=True)
+ info('done')
+
+ @abc.abstractmethod
+ def copy_files(self) -> None:
+ """Copy files."""
+
+ @abc.abstractmethod
+ def cleanup(self) -> None:
+ """Cleanup copied files."""
+
+ def run(self) -> None:
+ """Run the installer script."""
+ if self.upgrade:
+ check_call('python -m pip install --upgrade pip', shell=True)
+ check_call(
+ 'pip install --upgrade setuptools wheel twine ', shell=True)
+
+ if self.clear:
+ self.clear_old_dist()
+
+ if self.nodist:
+ return
+
+ self.copy_files()
+ try:
+ setup.main() # create a new package
+ except SystemExit as e:
+ error(e)
+ return
+ finally:
+ self.cleanup()
+
+ if self.local:
+ check_call('pip uninstall pywikibot -y', shell=True)
+ check_call(
+ 'pip install --no-index --pre --find-links=dist pywikibot',
+ shell=True)
+
+ if self.remote and input_yn(
+ '<<lightblue>>Upload dist to pypi', automatic_quit=False):
+ check_call('twine upload dist/*', shell=True)


-def copy_files() -> None: # pragma: no cover
- """Copy code entry point and i18n files to pywikibot.scripts folder.
+class SetupPywikibot(SetupBase):

- pwb.py wrapper script is a console script entry point for the
- site-package. pywikibot i18n files are used for some translations.
- They are copied to the pywikibot scripts folder.
+ """Setup for Pywikibot distribution.
+
+ .. versionadded:: 8.0
"""
- folder = Path().resolve()
- info(f'directory is {folder}')

- # copy script entry points to pywikibot\scripts
- target = folder / 'pywikibot' / 'scripts'
- filename = 'pwb.py'
- info(f'copy script entry point {filename!r} to {target}... ',
- newline=False)
- shutil.copy(folder / filename, target / filename)
- info('done')
+ def __init__(self, *args) -> None:
+ """Set source and target directories."""
+ super().__init__(*args)
+ source = self.folder / 'scripts' / 'i18n' / 'pywikibot'
+ target = self.folder / 'pywikibot' / 'scripts' / 'i18n' / 'pywikibot'
+ self.target = target
+ self.source = source

- target = target / 'i18n' / 'pywikibot'
- info(f'copy i18n files to {target} ... ', newline=False)
- target.parent.mkdir()
- filename = '__init__.py'
- shutil.copy(folder / 'scripts' / 'i18n' / filename,
- target.parent / filename)
- shutil.copytree(folder / 'scripts' / 'i18n' / 'pywikibot', target)
- info('done')
+ def copy_files(self) -> None: # pragma: no cover
+ """Copy i18n files to pywikibot.scripts folder.

+ Pywikibot i18n files are used for some translations. They are copied
+ to the pywikibot scripts folder.
+ """
+ info(f'directory is {self.folder}')
+ info(f'clear {self.target} directory')
+ shutil.rmtree(self.target, ignore_errors=True)
+ info('copy i18n files ... ', newline=False)
+ shutil.copytree(self.source, self.target)
+ info('done')

-def cleanup() -> None: # pragma: no cover
- """Remove all files which were copied to the pywikibot scripts folder."""
- info('Remove copied files... ', newline=False)
- folder = Path().resolve()
- target = folder / 'pywikibot' / 'scripts' / 'i18n'
- shutil.rmtree(target)
- target = target.parent / 'pwb.py'
- target.unlink()
- info('done')
+ def cleanup(self) -> None: # pragma: no cover
+ """Remove all copied files from pywikibot scripts folder."""
+ info('Remove copied files... ', newline=False)
+ shutil.rmtree(self.target)
+ # restore pywikibot en.json file
+ filename = 'en.json'
+ self.target.mkdir()
+ shutil.copy(self.source / filename, self.target / filename)
+ info('done')


def handle_args() -> Tuple[bool, bool, bool, bool, bool]:
@@ -134,37 +190,10 @@
return local, remote, clear, upgrade, nodist


-def main() -> None: # pragma: no cover
+def main() -> None:
"""Script entry point."""
- local, remote, clear, upgrade, nodist = handle_args()
-
- if upgrade:
- check_call('python -m pip install --upgrade pip', shell=True)
- check_call('pip install --upgrade setuptools wheel twine ', shell=True)
-
- if clear:
- clear_old_dist()
-
- if nodist:
- return
-
- copy_files()
- try:
- setup.main() # create a new package
- except SystemExit as e:
- error(e)
- return
- finally:
- cleanup()
-
- if local:
- check_call('pip uninstall pywikibot -y', shell=True)
- check_call('pip install --no-index --pre --find-links=dist pywikibot',
- shell=True)
-
- if remote and input_yn(
- '<<lightblue>>Upload dist to pypi', automatic_quit=False):
- check_call('twine upload dist/*', shell=True)
+ args = handle_args()
+ SetupPywikibot(*args).run()


if __name__ == '__main__': # pragma: no cover
diff --git a/pwb.py b/pwb.py
new file mode 100644
index 0000000..0e12919
--- /dev/null
+++ b/pwb.py
@@ -0,0 +1,36 @@
+"""pwb caller script to invoke the :mod:`pywikibot.scripts.wrapper` script.
+
+.. versionadded:: 8.0
+"""
+#
+# (C) Pywikibot team, 2022
+#
+# Distributed under the terms of the MIT license.
+#
+import sys
+
+VERSIONS_REQUIRED_MESSAGE = """
+Pywikibot is not available on:
+{version}
+
+This version of Pywikibot only supports Python 3.6.1+.
+"""
+
+
+def python_is_supported():
+ """Check that Python is supported."""
+ return sys.version_info[:3] >= (3, 6, 1)
+
+
+if not python_is_supported(): # pragma: no cover
+ sys.exit(VERSIONS_REQUIRED_MESSAGE.format(version=sys.version))
+
+
+def main():
+ """Entry point for :func:`tests.utils.execute_pwb`."""
+ from pywikibot.scripts import wrapper
+ wrapper.main()
+
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/pywikibot/scripts/wrapper.py b/pywikibot/scripts/wrapper.py
index 513f876..db59e06 100755
--- a/pywikibot/scripts/wrapper.py
+++ b/pywikibot/scripts/wrapper.py
@@ -1,5 +1,4 @@
#!/usr/bin/env python3
-# -*- coding: utf-8 -*-
"""Wrapper script to invoke pywikibot-based scripts.

This wrapper script invokes script by its name in this search order:
@@ -35,28 +34,25 @@
pwb wrapper was added to the Python site package lib
.. versionchanged:: 7.7
pwb wrapper is able to set ``PYWIKIBOT_TEST_...`` environment variables
+.. versionchanged:: 8.0
+ renamed to wrapper.py
"""
+#
# (C) Pywikibot team, 2012-2022
#
# Distributed under the terms of the MIT license.
#
-# ## KEEP PYTHON 2 SUPPORT FOR THIS SCRIPT ## #
-from __future__ import print_function
-
+#
import os
import sys
import types
from difflib import get_close_matches
from importlib import import_module
+from pathlib import Path
from time import sleep
from warnings import warn


-try:
- from pathlib import Path
-except ImportError:
- pass
-
pwb = None
site_package = False

@@ -184,6 +180,8 @@
for index, arg in enumerate(args, start=1):
if arg in ('-version', '--version'):
fname = 'version.py'
+ elif arg in ('pwb', 'pwb.py', 'wrapper', 'wrapper.py'):
+ pass
elif arg.startswith('-'):
local.append(arg)
elif arg.startswith('PYWIKIBOT_TEST_'):
@@ -291,8 +289,9 @@
# If successful, user config file already exists in one of the candidate
# directories. See config.py for details on search order.
# Use env var to communicate to config.py pwb.py location (bug T74918).
-_pwb_dir = os.path.split(__file__)[0]
-os.environ['PYWIKIBOT_DIR_PWB'] = _pwb_dir
+wrapper_dir = Path(__file__).parent
+os.environ['PYWIKIBOT_DIR_PWB'] = str(wrapper_dir)
+
try:
import pywikibot as pwb
except RuntimeError as e: # pragma: no cover
@@ -309,8 +308,8 @@

print('NOTE: user-config.py was not found!')
print('Please follow the prompts to create it:')
- run_python_file(os.path.join(
- _pwb_dir, 'pywikibot', 'scripts', 'generate_user_files.py'), [])
+ run_python_file(str(wrapper_dir.joinpath(
+ 'pywikibot', 'scripts', 'generate_user_files.py')), [])
# because we have loaded pywikibot without user-config.py loaded,
# we need to re-start the entire process. Ask the user to do so.
print('Now, you have to re-execute the command to start your script.')
@@ -335,12 +334,10 @@

scripts = {}

- script_paths = [['.']] + script_paths # add current directory
- for path in script_paths:
- folder = Path(_pwb_dir).joinpath(*path)
+ for folder in script_paths:
if not folder.exists(): # pragma: no cover
- warning('{} does not exists; remove it from user_script_paths'
- .format(folder))
+ warning(
+ f'{folder} does not exists; remove it from user_script_paths')
continue
for script_name in folder.iterdir():
name, suffix = script_name.stem, script_name.suffix
@@ -387,27 +384,17 @@
from pywikibot import config
path_list = [] # paths to find misspellings

- def test_paths(paths, root):
+ def test_paths(paths, root: Path):
"""Search for filename in given paths within 'root' base directory."""
for file_package in paths:
package = file_package.split('.')
path = package + [filename]
- testpath = os.path.join(root, *path)
- if os.path.exists(testpath):
- return testpath
- path_list.append(package)
+ testpath = root.joinpath(*path)
+ if testpath.exists():
+ return str(testpath)
+ path_list.append(testpath.parent)
return None

- if site_package: # pragma: no cover
- script_paths = [''] # only use the root as path
- else:
- script_paths = [
- 'scripts.userscripts',
- 'scripts',
- 'scripts.maintenance',
- 'pywikibot.scripts',
- ]
-
user_script_paths = []
if config.user_script_paths: # pragma: no cover
if isinstance(config.user_script_paths, list):
@@ -417,14 +404,25 @@
'found: {}. Ignoring this setting.'
.format(type(config.user_script_paths)))

- found = test_paths(user_script_paths, config.base_dir)
+ found = test_paths(user_script_paths, Path(config.base_dir))
if found: # pragma: no cover
return found

- found = test_paths(script_paths, _pwb_dir)
+ # search for system scripts in pywikibot.scripts directory
+ found = test_paths([''], wrapper_dir)
if found:
return found

+ if not site_package:
+ script_paths = [
+ 'scripts',
+ 'scripts.maintenance',
+ 'pywikibot.scripts',
+ ]
+ found = test_paths(script_paths, wrapper_dir.parents[1])
+ if found:
+ return found
+
return find_alternates(filename, path_list)


@@ -496,14 +494,8 @@
.. versionchanged:: 7.0
previous implementation was renamed to :func:`execute`
"""
- try:
- if not check_modules(): # pragma: no cover
- raise RuntimeError('') # no further output needed
- # setup.py may also raise RuntimeError
- except RuntimeError as e: # pragma: no cover
- sys.exit(e)
- except SyntaxError as e: # pragma: no cover
- sys.exit(str(e) + '\nProbably outdated Python version')
+ if not check_modules(): # pragma: no cover
+ sys.exit()

if not execute():
print(__doc__)
diff --git a/setup.py b/setup.py
index cfd23a5..ae5928d 100755
--- a/setup.py
+++ b/setup.py
@@ -27,6 +27,7 @@
import os
import re
import sys
+from setuptools import setup

if sys.version_info[:3] >= (3, 9):
List = list
@@ -34,28 +35,6 @@
from typing import List


-VERSIONS_REQUIRED_MESSAGE = """
-Pywikibot is not available on:
-{version}
-
-This version of Pywikibot only supports Python 3.6.1+.
-"""
-
-try:
- from setuptools import setup
-except SyntaxError:
- raise RuntimeError(VERSIONS_REQUIRED_MESSAGE.format(version=sys.version))
-
-
-def python_is_supported() -> bool:
- """Check that Python is supported."""
- return sys.version_info[:3] >= (3, 6, 1)
-
-
-if not python_is_supported(): # pragma: no cover
- # pwb.py checks this exception
- raise RuntimeError(VERSIONS_REQUIRED_MESSAGE.format(version=sys.version))
-
# ------- setup extra_requires ------- #
extra_deps = {
# Core library dependencies

To view, visit change 842929. To unsubscribe, or for help writing mail filters, visit settings.

Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Id9d7344e740bb848a4b0972d4f3b2362634dc1ba
Gerrit-Change-Number: 842929
Gerrit-PatchSet: 9
Gerrit-Owner: Xqt <info@gno.de>
Gerrit-Reviewer: JJMC89 <JJMC89.Wikimedia@gmail.com>
Gerrit-Reviewer: Xqt <info@gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged