XZise has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/164299

Change subject: [FEAT] Rewritten generate_user_files and Py3 support
......................................................................

[FEAT] Rewritten generate_user_files and Py3 support

This is a general overhaul of generate_user_files. The questions have
been rewritten to apear and work like one generated by 'inputChoice'.

It now also requires a non empty username (and doesn't default to
'UnnamedBot'). The default values when adding additional projects are
those of the main.

The default language of a project which only has one (e.g. commons) is
that language (and not 'en'). It'll require a confirmation when the
language is not known (and there are languages known).

All usernames are now by design together. Previously they could
have been separated by other config values in the extended mode.

It also supports now Python 3.

Change-Id: I5d8209d2357a6ebe90a55766a8ff27e953647738
---
M generate_user_files.py
1 file changed, 168 insertions(+), 126 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/pywikibot/core 
refs/changes/99/164299/1

diff --git a/generate_user_files.py b/generate_user_files.py
index d38cca0..7db4fd2 100644
--- a/generate_user_files.py
+++ b/generate_user_files.py
@@ -13,8 +13,10 @@
 import re
 import codecs
 import platform
+import math
 
-single_wiki_families = ['commons', 'wikidata']
+if sys.version_info[0] > 2:
+    raw_input = input
 
 
 def get_base_dir():
@@ -78,8 +80,9 @@
 
     message += u": "
 
+    line_template = u"{{0: >{0}}}: 
{{1}}".format(math.floor(math.log10(len(clist)) + 1))
     for n, i in enumerate(clist):
-        print(u"%d: %s" % (n + 1, i))
+        print(line_template.format(n + 1, i))
 
     while True:
         choice = raw_input(message)
@@ -89,23 +92,20 @@
         try:
             choice = int(choice)
         except ValueError:
-            # User typed choice name
-            if choice not in clist:
-                print("Invalid response")
-                continue
-            else:
-                return choice
+            try:
+                choice = clist.index(choice) + 1
+            except IndexError:
+                choice = 0
 
         # User typed choice number
         if 1 <= choice <= len(clist):
-                return clist[choice - 1]
+            return clist[choice - 1]
         else:
-                print("Invalid response")
+            print("Invalid response")
 
 
 def change_base_dir():
     """Create a new user directory."""
-    global base_dir
     while True:
         new_base = raw_input("New user directory? ")
         new_base = os.path.abspath(new_base)
@@ -137,10 +137,9 @@
 set environment variables.""" % locals(), width=76)
     for line in msg:
         print(line)
-    ok = raw_input("Is this OK? ([y]es, [N]o) ")
-    if ok in ["Y", "y"]:
-        base_dir = new_base
-        return True
+    ok = raw_input("Is this OK? ([y]es, [N]o) ").lower()
+    if ok in ["y", "yes"]:
+        return new_base
     print("Aborting changes.")
     return False
 
@@ -152,88 +151,92 @@
     return False
 
 
-def get_site_and_lang():
-        known_families = re.findall(
-            r'(.+)_family.py\b',
-            '\n'.join(os.listdir(os.path.join(
-                pywikibot_dir,
-                "pywikibot",
-                "families")))
-        )
-        known_families = sorted(known_families)
-        fam = listchoice(known_families,
-                         u"Select family of sites we are working on, "
-                         u"just enter the number not name",
-                         default=u'wikipedia')
-        if fam not in single_wiki_families:
-            codesds = codecs.open(os.path.join(pywikibot_dir,
-                                               u"pywikibot",
-                                               u"families",
-                                               u"%s_family.py" % fam),
-                                  "r", "utf-8").read()
-            rre = re.compile(u"self\.languages\_by\_size *\= *(.+?)\]",
-                             re.DOTALL)
-            known_langs = []
-            if not rre.findall(codesds):
-                rre = re.compile(u"self\.langs *\= *(.+?)\}", re.DOTALL)
-                if rre.findall(codesds):
-                    import ast
-                    known_langs = ast.literal_eval(
-                        rre.findall(codesds)[0] + u"}").keys()
-            else:
-                known_langs = eval(rre.findall(codesds)[0] + u"]")
-            print("This is the list of known language(s):")
-            print(u" ".join(sorted(known_langs)))
-            mylang = raw_input("The language code of the site we're working on 
"
-                               "(default: 'en'): ") or 'en'
+def get_site_and_lang(default_family='wikipedia', default_lang='en',
+                      default_username=None):
+    """
+    Ask the user for the family, language and username.
+
+    @param default_family: The default family which should be chosen.
+    @type default_family: None or str
+    @param default_lang: The default language which should be chosen, if the
+        family supports this language.
+    @type default_lang: None or str
+    @param default_username: The default username which should be chosen.
+    @type default_username: None or str
+    @return: The family, language and username
+    @rtype: tuple of three str
+    """
+    family_file = re.compile(r'^(.+)_family.py$')
+    family_matches = (family_file.match(f) for f in os.listdir(os.path.join(
+        pywikibot_dir, "pywikibot", "families")))
+    known_families = sorted(m.group(1) for m in family_matches if m)
+    if default_family not in known_families:
+        default_family = None
+    fam = listchoice(known_families,
+                     u"Select family of sites we are working on, "
+                     u"just enter the number not name",
+                     default=default_family)
+    with codecs.open(os.path.join(pywikibot_dir,
+                                  "pywikibot",
+                                  "families",
+                                  "%s_family.py" % fam),
+                     "r", "utf-8") as f:
+        codesds = f.read()
+    rre = re.search(r"self\.languages_by_size *= *(.+?\])", codesds,
+                    re.DOTALL)
+    if not rre:
+        rre = re.search(u"self\.langs *= *(.+?\})", codesds, re.DOTALL)
+        if rre:
+            import ast
+            known_langs = list(ast.literal_eval(rre.group(1)).keys())
         else:
-            mylang = fam
+            known_langs = []
+    else:
+        known_langs = eval(rre.group(1))
+    if len(known_langs) == 0:
+        print('There were no known languages found in {0}.'.format(fam))
+        default_lang = None
+    elif len(known_langs) == 1:
+        print('The only known language: {0}'.format(known_langs[0]))
+        default_lang = known_langs[0]
+    else:
+        print("This is the list of known languages:")
+        print(u", ".join(sorted(known_langs)))
+        if default_lang not in known_langs:
+            if default_lang != 'en' and 'en' in known_langs:
+                default_lang = 'en'
+            else:
+                default_lang = None
+    message = "The language code of the site we're working on"
+    if default_lang:
+        message += " (default: '{0}')".format(default_lang)
+    message += ": "
+    mylang = None
+    while not mylang:
+        mylang = raw_input(message) or default_lang
+        if known_langs and mylang and mylang not in known_langs:
+            choice = raw_input("The language code {0} is not in the list of "
+                               "known languages. Do you want to continue? "
+                               "([y]es, [N]o) ".format(mylang)).lower()
+            if choice not in ['yes', 'y']:
+                mylang = None
 
-        username = raw_input(u"Username (%s %s): "
-                             % (mylang, fam))
-        username = unicode(username, console_encoding)
-        return fam, mylang, username
+    username = None
+    message = u"Username on {0}:{1}".format(mylang, fam)
+    if default_username:
+        message += " (default: '{0}')".format(default_username)
+    message += ": "
+    while not username:
+        username = raw_input(message) or default_username
+        if not username:
+            print('The username may not be empty.')
+    if sys.version_info == 2:
+        username = username.decode(console_encoding)
+    # Escape ''s
+    username = username.replace("'", "\\'")
+    return fam, mylang, username
 
-
-def create_user_config():
-    _fnc = os.path.join(base_dir, "user-config.py")
-    if not file_exists(_fnc):
-        fam, mylang, mainusername = get_site_and_lang()
-        mainusername = mainusername or "UnnamedBot"
-
-        while True:
-            choice = raw_input(
-                "Which variant of user_config.py:\n"
-                "[S]mall or [E]xtended (with further information)? ").upper()
-            if choice in "SE":
-                break
-
-        # determine what directory this script (generate_user_files.py) lives 
in
-        install = os.path.dirname(os.path.abspath(__file__))
-        # config2.py will be in the pywikibot/ directory
-        f = codecs.open(os.path.join(install, "pywikibot", "config2.py"),
-                        "r", "utf-8")
-        cpy = f.read()
-        f.close()
-
-        res = re.findall("^(############## (?:"
-                         "LOGFILE|"
-                         "INTERWIKI|"
-                         "SOLVE_DISAMBIGUATION|"
-                         "IMAGE RELATED|"
-                         "TABLE CONVERSION BOT|"
-                         "WEBLINK CHECKER|"
-                         "DATABASE|"
-                         "SEARCH ENGINE|"
-                         "COPYRIGHT|"
-                         "FURTHER"
-                         ") SETTINGS .*?)^(?=#####|# =====)",
-                         cpy, re.MULTILINE | re.DOTALL)
-        config_text = '\n'.join(res)
-
-        f = codecs.open(_fnc, "w", "utf-8")
-        if choice == 'E':
-            f.write(u"""# -*- coding: utf-8  -*-
+EXTENDED_CONFIG = u"""# -*- coding: utf-8  -*-
 
 # This is an automatically generated file. You can find more configuration
 # parameters in 'config.py' file.
@@ -266,34 +269,76 @@
 # If you use either of these functions to define the family to work on by
 # default (the ‘family’ variable below), you must place the function call
 # before the definition of the ‘family’ variable.
-family = '%s'
+family = '{main_family}'
 
 # The language code of the site we're working on.
-mylang = '%s'
+mylang = '{main_lang}'
 
 # The dictionary usernames should contain a username for each site where you
 # have a bot account. If you have a unique username for all languages of a
 # family , you can use '*'
-usernames['%s']['%s'] = u'%s'
+{usernames}
 
 
-%s""" % (fam, mylang, fam, mylang, mainusername, config_text))
+{config_text}"""
+
+SMALL_CONFIG = (u"# -*- coding: utf-8  -*-\n"
+                u"family = '{main_family}'\n"
+                u"mylang = '{main_lang}'\n"
+                u"{usernames}\n")
+
+
+def create_user_config():
+    _fnc = os.path.join(base_dir, "user-config.py")
+    if not file_exists(_fnc):
+        main_family, main_lang, main_username = get_site_and_lang()
+
+        usernames = [(main_family, main_lang, main_username)]
+        while raw_input("Do you want to add any other projects? "
+                        "([y]es, [N]o) ").lower() in ["y", "yes"]:
+            usernames += [get_site_and_lang(main_family, main_lang,
+                                            main_username)]
+
+        usernames = '\n'.join(u"usernames['{0}']['{1}'] = 
u'{2}'".format(*username) for username in usernames)
+
+        extended = None
+        while extended is None:
+            choice = raw_input(
+                "Which variant of user_config.py:\n"
+                "[s]mall or [e]xtended (with further information)? ").lower()
+            if choice in ['s', 'small']:
+                extended = False
+            elif choice in ['e', 'extended']:
+                extended = True
+
+        if extended:
+            # config2.py will be in the pywikibot/ directory relative to this
+            # script (generate_user_files)
+            install = os.path.dirname(os.path.abspath(__file__))
+            with codecs.open(os.path.join(install, "pywikibot", "config2.py"),
+                             "r", "utf-8") as config_f:
+                config = config_f.read()
+
+            res = re.findall("^(############## (?:"
+                             "LOGFILE|"
+                             "INTERWIKI|"
+                             "SOLVE_DISAMBIGUATION|"
+                             "IMAGE RELATED|"
+                             "TABLE CONVERSION BOT|"
+                             "WEBLINK CHECKER|"
+                             "DATABASE|"
+                             "SEARCH ENGINE|"
+                             "COPYRIGHT|"
+                             "FURTHER"
+                             ") SETTINGS .*?)^(?=#####|# =====)",
+                             config, re.MULTILINE | re.DOTALL)
+            config_text = '\n'.join(res)
+            config_content = EXTENDED_CONFIG
         else:
-            f.write(u"""# -*- coding: utf-8  -*-
-family = '%s'
-mylang = '%s'
-usernames['%s']['%s'] = u'%s'
-""" % (fam, mylang, fam, mylang, mainusername))
-        while(raw_input(
-                "Do you want to add any other projects? (y/N)").upper() == 
"Y"):
-            fam, mylang, username = get_site_and_lang()
-            username = username or mainusername
-            # Escape ''s
-            username = username.replace("'", "\\'")
-            f.write(u"usernames['%(fam)s']['%(mylang)s'] = u'%(username)s'\n"
-                    % locals())
+            config_content = SMALL_CONFIG
 
-        f.close()
+        with codecs.open(_fnc, "w", "utf-8") as f:
+            f.write(config_content.format(**locals()))
         print(u"'%s' written." % _fnc)
 
 
@@ -327,14 +372,16 @@
         if (not ok) or "KEEP".startswith(ok):
             break
         if "CHANGE".startswith(ok):
-            if change_base_dir():
+            new_base = change_base_dir()
+            if new_base:
+                base_dir = new_base
                 break
     while True:
         if os.path.exists(os.path.join(base_dir, "user-config.py")):
             break
         do_copy = raw_input("Do you want to copy user files from an existing "
-                            "Pywikibot installation? ").upper().strip()
-        if do_copy and "YES".startswith(do_copy):
+                            "Pywikibot installation? ([y]es, [n]o) ").lower()
+        if do_copy in ['y', 'yes']:
             oldpath = raw_input("Path to existing wikipedia.py? ")
             if not os.path.exists(oldpath):
                 print("ERROR: Not a valid path")
@@ -345,20 +392,15 @@
             if not os.path.isfile(os.path.join(oldpath, "user-config.py")):
                 print("ERROR: no user_config.py found in that directory")
                 continue
-            newf = file(os.path.join(base_dir, "user-config.py"), "wb")
-            oldf = file(os.path.join(oldpath, "user-config.py"), "rb")
-            newf.write(oldf.read())
-            newf.close()
-            oldf.close()
+            import shutil
+            shutil.copyfile(os.path.join(base_dir, "user-config.py"),
+                            os.path.join(oldpath, "user-config.py"))
 
             if os.path.isfile(os.path.join(oldpath, "user-fixes.py")):
-                newfix = file(os.path.join(base_dir, "user-fixes.py"), "wb")
-                oldfix = file(os.path.join(oldpath, "user-fixes.py"), "rb")
-                newfix.write(oldfix.read())
-                newfix.close()
-                oldfix.close()
+                shutil.copyfile(os.path.join(base_dir, "user-fixes.py"),
+                                os.path.join(oldpath, "user-fixes.py"))
 
-        elif do_copy and "NO".startswith(do_copy):
+        elif do_copy in ['n', 'no']:
             break
     if not os.path.isfile(os.path.join(base_dir, "user-config.py")):
         a = raw_input("Create user-config.py file? Required for running bots "

-- 
To view, visit https://gerrit.wikimedia.org/r/164299
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I5d8209d2357a6ebe90a55766a8ff27e953647738
Gerrit-PatchSet: 1
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: XZise <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to