jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/628100 )
Change subject: [IMPR] Improvements for threadedhttp.py
......................................................................
[IMPR] Improvements for threadedhttp.py
- remove code duplication for trying raw.decode
- use a clearer logic for the self.header_encoding
- add some type hints
- fix _logger string
- fix single char alternation in encoding regex
- update CONTENT.rst
- update doc strings in api.py
Change-Id: Ia133df34d6dfc72e054b372a925fcf1774f0d46d
---
M pywikibot/CONTENT.rst
M pywikibot/comms/threadedhttp.py
M pywikibot/data/api.py
3 files changed, 43 insertions(+), 43 deletions(-)
Approvals:
Mpaa: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/CONTENT.rst b/pywikibot/CONTENT.rst
index de541b7..a192929 100644
--- a/pywikibot/CONTENT.rst
+++ b/pywikibot/CONTENT.rst
@@ -82,7 +82,7 @@
+----------------------------+------------------------------------------------------+
| http.py | Basic HTTP access interface |
+----------------------------+------------------------------------------------------+
- | threadedhttp.py | Httplib2 threaded cookie layer extending httplib2 |
+ | threadedhttp.py | HTTP requests wrapper |
+----------------------------+------------------------------------------------------+
diff --git a/pywikibot/comms/threadedhttp.py b/pywikibot/comms/threadedhttp.py
index fd19f5d..8b4338e 100644
--- a/pywikibot/comms/threadedhttp.py
+++ b/pywikibot/comms/threadedhttp.py
@@ -1,5 +1,5 @@
# -*- coding: utf-8 -*-
-"""Http backend layer, formerly providing a httplib2 wrapper."""
+"""Http backend layer providing a HTTP requests wrapper."""
#
# (C) Pywikibot team, 2007-2020
#
@@ -8,13 +8,14 @@
import codecs
import re
+from typing import Dict, Optional
from urllib.parse import urlparse
import pywikibot
from pywikibot.tools import deprecated
-_logger = 'comm.threadedhttp'
+_logger = 'comms.threadedhttp'
class HttpRequest:
@@ -28,8 +29,7 @@
def __init__(self, uri, method='GET', params=None, body=None, headers=None,
callbacks=None, charset=None, **kwargs):
- """
- Initializer.
+ """Initializer.
See C{Http.request} for parameters.
"""
@@ -71,17 +71,17 @@
callback(self)
@property
- def exception(self):
+ def exception(self) -> Optional[Exception]:
"""Get the exception, if any."""
return self.data if isinstance(self.data, Exception) else None
@property
- def response_headers(self):
+ def response_headers(self) -> Optional[Dict[str, str]]:
"""Return the response headers."""
return self.data.headers if not self.exception else None
@property
- def raw(self):
+ def raw(self) -> Optional[bytes]:
"""Return the raw response body."""
return self.data.content if not self.exception else None
@@ -119,9 +119,9 @@
# application/json | application/sparql-results+json
self._header_encoding = 'utf-8'
elif 'xml' in content_type:
- header = self.raw[:100].splitlines()[0] # bytestr in py3
- m = re.search(br'encoding=("|'
- br"')(?P<encoding>.+?)\1", header)
+ header = self.raw[:100].splitlines()[0] # bytes
+ m = re.search(
+ br'encoding=(["\'])(?P<encoding>.+?)\1', header)
if m:
self._header_encoding = m.group('encoding').decode('utf-8')
else:
@@ -134,63 +134,64 @@
def encoding(self):
"""Detect the response encoding."""
if not hasattr(self, '_encoding'):
- if not self.charset and not self.header_encoding:
+ if self.charset is None and self.header_encoding is None:
pywikibot.log("Http response doesn't contain a charset.")
charset = 'latin1'
else:
charset = self.charset
- lookup = codecs.lookup(charset) if charset else None
- if (self.header_encoding
- and (lookup is None
- or codecs.lookup(self.header_encoding) != lookup)):
+
+ if self.header_encoding is not None \
+ and (charset is None
+ or codecs.lookup(self.header_encoding)
+ != codecs.lookup(charset)):
if charset:
pywikibot.warning(
- 'Encoding "{}" requested but "{}" '
- 'received in the header.'
- .format(charset, self.header_encoding))
- try:
- # TODO: Buffer decoded content, weakref does remove it too
- # early (directly after this method)
- self.raw.decode(self.header_encoding)
- except UnicodeError as e:
- self._encoding = e
- else:
- self._encoding = self.header_encoding
+ 'Encoding "{}" requested but "{}" received in the '
+ 'header.'.format(charset, self.header_encoding))
+
+ # TODO: Buffer decoded content, weakref does remove it too
+ # early (directly after this method)
+ self._encoding = self._try_decode(self.header_encoding)
else:
self._encoding = None
if charset and (isinstance(self._encoding, Exception)
- or not self._encoding):
- try:
- self.raw.decode(charset)
- except UnicodeError as e:
- self._encoding = e
- else:
- self._encoding = charset
+ or self._encoding is None):
+ self._encoding = self._try_decode(charset)
if isinstance(self._encoding, Exception):
raise self._encoding
return self._encoding
- def decode(self, encoding, errors='strict'):
+ def _try_decode(self, encoding):
+ """Helper function to try decoding."""
+ try:
+ self.raw.decode(encoding)
+ except UnicodeError as e:
+ result = e
+ else:
+ result = encoding
+ return result
+
+ def decode(self, encoding, errors='strict') -> str:
"""Return the decoded response."""
return self.raw.decode(encoding, errors)
@property
@deprecated('the `text` property', since='20180321')
- def content(self):
+ def content(self) -> str:
"""DEPRECATED. Return the response decoded by the detected encoding."""
return self.text
@property
- def text(self):
+ def text(self) -> str:
"""Return the response decoded by the detected encoding."""
return self.decode(self.encoding)
- def __str__(self):
+ def __str__(self) -> str:
"""Return the response decoded by the detected encoding."""
return self.text
- def __bytes__(self):
+ def __bytes__(self) -> Optional[bytes]:
"""Return the undecoded response."""
return self.raw
diff --git a/pywikibot/data/api.py b/pywikibot/data/api.py
index e7be358..a402843 100644
--- a/pywikibot/data/api.py
+++ b/pywikibot/data/api.py
@@ -2979,9 +2979,8 @@
"""Login to the site.
Note, this doesn't actually return or do anything with cookies.
- The threadedhttp module takes care of all the cookie stuff,
- this just has a legacy name for now and should be renamed in the
- future.
+ The http module takes care of all the cookie stuff, this just
+ has a legacy name for now and should be renamed in the future.
@return: empty string if successful, throws exception on failure
"""
@@ -3084,7 +3083,7 @@
raise APIError(code=status, info=info)
def storecookiedata(self, data):
- """Ignore data; cookies are set by threadedhttp module."""
+ """Ignore data; cookies are set by http module."""
http.cookie_jar.save(ignore_discard=True)
def get_login_token(self) -> str:
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/628100
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Ia133df34d6dfc72e054b372a925fcf1774f0d46d
Gerrit-Change-Number: 628100
Gerrit-PatchSet: 10
Gerrit-Owner: Xqt <info(a)gno.de>
Gerrit-Reviewer: Merlijn van Deen <valhallasw(a)arctus.nl>
Gerrit-Reviewer: Mpaa <mpaa.wiki(a)gmail.com>
Gerrit-Reviewer: Russell Blau <russblau(a)imapmail.org>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/634503 )
Change subject: [bugfix] api.APIError() called without enough args
......................................................................
[bugfix] api.APIError() called without enough args
Fixed also typos in docstrings.
Change-Id: Iba9bce7bef59a6400fcac028cd6078fa4846609e
---
M pywikibot/site/__init__.py
1 file changed, 8 insertions(+), 8 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/site/__init__.py b/pywikibot/site/__init__.py
index 601ada6..a4271c6 100644
--- a/pywikibot/site/__init__.py
+++ b/pywikibot/site/__init__.py
@@ -2385,7 +2385,7 @@
"""Iterate global image usage for a given FilePage.
@param page: the page to return global image usage for.
- @type image: pywikibot.FilePage
+ @type page: pywikibot.FilePage
@param total: iterate no more than this number of pages in total.
@raises TypeError: input page is not a FilePage.
@raises pywikibot.exceptions.SiteDefinitionError: Site could not be
@@ -2508,7 +2508,7 @@
for the given action type.
@param page: a pywikibot.Page object
- @type param: pywikibot.Page
+ @type page: pywikibot.Page
@param action: a valid restriction type like 'edit', 'move'
@type action: str
@rtype: bool
@@ -6193,8 +6193,8 @@
@see: U{https://www.mediawiki.org/wiki/API:Protectedtitles}
- @param namespaces: The searched namespace.
- @type namespaces: int or Namespace or str
+ @param namespace: The searched namespace.
+ @type namespace: int or Namespace or str
@param type: The protection type to search for (default 'edit').
@type type: str
@param level: The protection level (like 'autoconfirmed'). If False it
@@ -6299,7 +6299,7 @@
"""Return a generator to pages containing linter errors.
@param lint_categories: categories of lint errors
- @type lntcategories: an iterable that returns values (str),
+ @type lint_categories: an iterable that returns values (str),
or a pipe-separated string of values.
@param total: if not None, yielding this many items in total
@@ -6364,7 +6364,7 @@
source=source)
data = req.submit()
if data['result']['success'] != 1:
- raise api.APIError('Thanking unsuccessful')
+ raise api.APIError('Thanking unsuccessful', '')
return data
@need_extension('Flow')
@@ -6383,7 +6383,7 @@
postid=post_id, token=token)
data = req.submit()
if data['result']['success'] != 1:
- raise api.APIError('Thanking unsuccessful')
+ raise api.APIError('Thanking unsuccessful', '')
return data
# Flow API calls
@@ -7083,7 +7083,7 @@
req = self._simple_request(**params)
data = req.submit()
if 'success' not in data:
- raise api.APIError(data['errors'])
+ raise api.APIError(data['errors'], '')
return data['entities']
def preload_entities(self, pagelist, groupsize=50):
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/634503
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: Iba9bce7bef59a6400fcac028cd6078fa4846609e
Gerrit-Change-Number: 634503
Gerrit-PatchSet: 1
Gerrit-Owner: Mpaa <mpaa.wiki(a)gmail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/634344 )
Change subject: [IMPR] Replaced basestring by str
......................................................................
[IMPR] Replaced basestring by str
Bug: T265128
Change-Id: I5f365ca1e9c1e55398d7012a323afe908bbed845
---
M pywikibot/userinterfaces/gui.py
M pywikibot/userinterfaces/terminal_interface_base.py
M pywikibot/userinterfaces/transliteration.py
M scripts/add_text.py
M scripts/archivebot.py
M scripts/basic.py
6 files changed, 29 insertions(+), 54 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/userinterfaces/gui.py b/pywikibot/userinterfaces/gui.py
index 6eebc62..98b7a88 100644
--- a/pywikibot/userinterfaces/gui.py
+++ b/pywikibot/userinterfaces/gui.py
@@ -12,6 +12,7 @@
import tkinter
from tkinter.scrolledtext import ScrolledText
from tkinter import simpledialog as tkSimpleDialog
+from typing import Optional, Tuple
import pywikibot
from pywikibot import __url__
@@ -370,15 +371,14 @@
self.parent.config(menu=menubar)
self.pack()
- def edit(self, text: str, jumpIndex=None, highlight=None):
+ def edit(self, text: str, jumpIndex: Optional[int] = None,
+ highlight: Optional[str] = None):
"""
Provide user with editor to modify text.
@param text: the text to be edited
@param jumpIndex: position at which to put the caret
- @type jumpIndex: int
@param highlight: each occurrence of this substring will be highlighted
- @type highlight: str
@return: the modified text, or None if the user didn't save the text
file in his text editor
@rtype: str or None
@@ -583,11 +583,10 @@
self.skip = True
self.root.destroy()
- def show_dialog(self):
+ def show_dialog(self) -> Tuple[str, str, bool]:
"""Activate the dialog.
@return: new description, name, and if the image is skipped
- @rtype: tuple of (str, str, bool)
"""
self.root.mainloop()
return self.photo_description, self.filename, self.skip
diff --git a/pywikibot/userinterfaces/terminal_interface_base.py b/pywikibot/userinterfaces/terminal_interface_base.py
index 4c29233..9aebd99 100755
--- a/pywikibot/userinterfaces/terminal_interface_base.py
+++ b/pywikibot/userinterfaces/terminal_interface_base.py
@@ -12,6 +12,8 @@
import sys
import threading
+from typing import Optional
+
import pywikibot
from pywikibot import config2 as config
from pywikibot.bot import VERBOSE, INFO, STDOUT, INPUT, WARNING
@@ -238,7 +240,8 @@
# May be overridden by subclass
return input()
- def input(self, question, password=False, default='', force=False):
+ def input(self, question: str, password: bool = False,
+ default: str = '', force: bool = False) -> str:
"""
Ask the user a question and return the answer.
@@ -249,15 +252,10 @@
a trailing question mark.
@param question: The question, without trailing whitespace.
- @type question: basestring
@param password: if True, hides the user's input (for password entry).
- @type password: bool
@param default: The default answer if none was entered. None to require
an answer.
- @type default: basestring
@param force: Automatically use the default
- @type force: bool
- @rtype: str
"""
assert(not password or not default)
end_marker = ':'
@@ -300,8 +298,9 @@
raise QuitKeyboardInterrupt()
return text
- def input_choice(self, question, options, default=None,
- return_shortcut=True, automatic_quit=True, force=False):
+ def input_choice(self, question: str, options, default: str = None,
+ return_shortcut: bool = True,
+ automatic_quit: bool = True, force: bool = False):
"""
Ask the user and returns a value from the options.
@@ -310,7 +309,6 @@
ambiguous index.
@param question: The question, without trailing whitespace.
- @type question: basestring
@param options: Iterable of all available options. Each entry contains
the full length answer and a shortcut of only one character.
Alternatively they may be Option (or subclass) instances or
@@ -321,19 +319,15 @@
Singletons of Option and its subclasses are also accepted.
@param default: The default answer if no was entered. None to require
an answer.
- @type default: basestring
@param return_shortcut: Whether the shortcut or the index in the option
should be returned.
- @type return_shortcut: bool
@param automatic_quit: Adds the option 'Quit' ('q') if True and throws
a L{QuitKeyboardInterrupt} if selected.
- @type automatic_quit: bool
@param force: Automatically use the default
- @type force: bool
@return: If return_shortcut the shortcut of options or the value of
default (if it's not None). Otherwise the index of the answer in
options. If default is not a shortcut, it'll return -1.
- @rtype: int (if not return_shortcut), lowercased basestring (otherwise)
+ @rtype: int (if not return_shortcut), lowercased str (otherwise)
"""
if force and default is None:
raise ValueError('With no default option it cannot be forced')
@@ -406,17 +400,15 @@
else:
pywikibot.error('Invalid response')
- def editText(self, text, jumpIndex=None, highlight=None):
+ def editText(self, text: str, jumpIndex: Optional[int] = None,
+ highlight: Optional[str] = None):
"""Return the text as edited by the user.
Uses a Tkinter edit box because we don't have a console editor
@param text: the text to be edited
- @type text: str
@param jumpIndex: position at which to put the caret
- @type jumpIndex: int
@param highlight: each occurrence of this substring will be highlighted
- @type highlight: str
@return: the modified text, or None if the user didn't save the text
file in his text editor
@rtype: str or None
diff --git a/pywikibot/userinterfaces/transliteration.py b/pywikibot/userinterfaces/transliteration.py
index 7a8b445..c7b6abb 100644
--- a/pywikibot/userinterfaces/transliteration.py
+++ b/pywikibot/userinterfaces/transliteration.py
@@ -1110,17 +1110,15 @@
trans[char] = value
self.trans = trans
- def transliterate(self, char: str, default='?', prev='-', next='-') -> str:
+ def transliterate(self, char: str, default: str = '?',
+ prev: str = '-', next: str = '-') -> str:
"""
Transliterate the character.
@param char: The character to transliterate.
@param default: The character used when there is no transliteration.
- @type default: str
@param prev: The previous character
- @type prev: str
@param next: The next character
- @type next: str
@return: The transliterated character which may be an empty string
"""
if char in self.trans:
diff --git a/scripts/add_text.py b/scripts/add_text.py
index 53709d2..c7fff8f 100755
--- a/scripts/add_text.py
+++ b/scripts/add_text.py
@@ -74,7 +74,7 @@
docuReplacements = {'¶ms;': pagegenerators.parameterHelp} # noqa: N816
-def get_text(page, old, create) -> str:
+def get_text(page, old: str, create: bool) -> str:
"""
Get text on page. If old is not None, return old.
@@ -82,9 +82,7 @@
@type page: pywikibot.page.BasePage
@param old: If not None, this parameter is returned instead
of fetching text from the page
- @type old: str
@param create: Create the page if it doesn't exist
- @type create: bool
@return: The page's text or old parameter if not None
"""
if old is None:
@@ -107,20 +105,17 @@
return text
-def put_text(page, new, summary, count, asynchronous=False) -> Optional[bool]:
+def put_text(page, new: str, summary: str, count: int,
+ asynchronous: bool = False) -> Optional[bool]:
"""
Save the new text.
@param page: The page to update and save
@type page: pywikibot.page.BasePage
@param new: The new text for the page
- @type new: str
@param summary: Summary of page changes.
- @type summary: str
@param count: Maximum num attempts to reach the server
- @type count: int
@param asynchronous: Save the page asynchronously
- @type asynchronous: bool
@return: True if successful, False if unsuccessful, None if
waiting for server
"""
@@ -151,9 +146,12 @@
return False
-def add_text(page, addText, summary=None, regexSkip=None,
- regexSkipUrl=None, always=False, up=False, putText=True,
- oldTextGiven=None, reorderEnabled=True, create=False
+def add_text(page, addText: str, summary: Optional[str] = None,
+ regexSkip: Optional[str] = None,
+ regexSkipUrl: Optional[str] = None,
+ always: bool = False, up: bool = False,
+ putText: bool = True, oldTextGiven: Optional[str] = None,
+ reorderEnabled: bool = True, create: bool = False
) -> Union[Tuple[bool, bool, bool], Tuple[str, str, bool]]:
"""
Add text to a page.
@@ -161,27 +159,17 @@
@param page: The page to add text to
@type page: pywikibot.page.BasePage
@param addText: Text to add
- @type addText: str
@param summary: Summary of changes. If None, beginning of addText is used.
- @type summary: str
@param regexSkip: Abort if text on page matches
- @type regexSkip: str
@param regexSkipUrl: Abort if full url matches
- @type regexSkipUrl: str
@param always: Always add text without user confirmation
- @type always: bool
@param up: If True, add text to top of page, else add at bottom.
- @type up: bool
@param putText: If True, save changes to the page, else return
(text, newtext, always)
- @type putText: bool
@param oldTextGiven: If None fetch page text, else use this text
- @type oldTextGiven: str
@param reorderEnabled: If True place text above categories and
interwiki, else place at page bottom. No effect if up = False.
- @type reorderEnabled: bool
@param create: Create page if it does not exist
- @type create: bool
@return: If putText=True: (success, success, always)
else: (text, newtext, always)
"""
@@ -282,14 +270,13 @@
error_count += 1
-def main(*args) -> None:
+def main(*args: Tuple[str, ...]) -> None:
"""
Process command line arguments and invoke bot.
If args is an empty list, sys.argv is used.
@param args: command line arguments
- @type args: str
"""
# If none, the var is set only for check purpose.
summary = None
diff --git a/scripts/archivebot.py b/scripts/archivebot.py
index 8b15bd0..efe4802 100755
--- a/scripts/archivebot.py
+++ b/scripts/archivebot.py
@@ -191,7 +191,6 @@
7d - 7 days
2w - 2 weeks (14 days)
1y - 1 year
- @type string: str
@param timestamp: a timestamp to calculate a more accurate duration offset
used by years
@type timestamp: datetime.datetime
@@ -231,7 +230,6 @@
7d - 7 days
2w - 2 weeks (14 days)
1y - 1 year
- @type string: str
@return: key and duration extracted form the string
"""
if string.isdigit():
diff --git a/scripts/basic.py b/scripts/basic.py
index 8d14573..3f859ef 100755
--- a/scripts/basic.py
+++ b/scripts/basic.py
@@ -33,6 +33,8 @@
#
# Distributed under the terms of the MIT license.
#
+from typing import Tuple
+
import pywikibot
from pywikibot import pagegenerators
@@ -121,14 +123,13 @@
self.put_current(text, summary=self.opt.summary)
-def main(*args) -> None:
+def main(*args: Tuple[str, ...]) -> None:
"""
Process command line arguments and invoke bot.
If args is an empty list, sys.argv is used.
@param args: command line arguments
- @type args: str
"""
options = {}
# Process global arguments to determine desired site
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/634344
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I5f365ca1e9c1e55398d7012a323afe908bbed845
Gerrit-Change-Number: 634344
Gerrit-PatchSet: 3
Gerrit-Owner: Udoka <UdokakuUgochukwu(a)gmail.com>
Gerrit-Reviewer: D3r1ck01 <xsavitar.wiki(a)aol.com>
Gerrit-Reviewer: Dr0ptp4kt <abaso(a)wikimedia.org>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/634285 )
Change subject: [IMPR] Replaced basestring to str
......................................................................
[IMPR] Replaced basestring to str
Bug: T265128
Change-Id: I548cb45e6b147ddcda7930c379040482070765ec
---
M generate_user_files.py
M pywikibot/__init__.py
M pywikibot/bot_choice.py
3 files changed, 31 insertions(+), 52 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/generate_user_files.py b/generate_user_files.py
index f8437f2..7d5a7bf 100755
--- a/generate_user_files.py
+++ b/generate_user_files.py
@@ -11,6 +11,8 @@
import re
import sys
+from typing import Optional, Tuple
+
from collections import namedtuple
from textwrap import fill
@@ -95,18 +97,16 @@
return False
-def get_site_and_lang(default_family='wikipedia', default_lang='en',
- default_username=None, force=False):
+def get_site_and_lang(default_family: Optional[str] = 'wikipedia',
+ default_lang: Optional[str] = 'en',
+ default_username: Optional[str] = None, force=False):
"""
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
"""
@@ -425,14 +425,13 @@
return userfile, passfile
-def main(*args):
+def main(*args: Tuple[str, ...]):
"""
Process command line arguments and generate user-config.
If args is an empty list, sys.argv is used.
@param args: command line arguments
- @type args: str
"""
# set the config family and mylang values to an invalid state so that
# the script can detect that the command line arguments -family & -lang
diff --git a/pywikibot/__init__.py b/pywikibot/__init__.py
index b552b49..7f83449 100644
--- a/pywikibot/__init__.py
+++ b/pywikibot/__init__.py
@@ -133,11 +133,10 @@
return cls._ISO8601Format()
@classmethod
- def _ISO8601Format(cls, sep='T'):
+ def _ISO8601Format(cls, sep: str = 'T'):
"""ISO8601 format string.
@param sep: one-character separator, placed between the date and time
- @type sep: str
@return: ISO8601 format string
@rtype: str
"""
@@ -145,13 +144,12 @@
return '%Y-%m-%d{0}%H:%M:%SZ'.format(sep)
@classmethod
- def fromISOformat(cls, ts, sep='T'):
+ def fromISOformat(cls, ts, sep: str = 'T'):
"""Convert an ISO 8601 timestamp to a Timestamp object.
@param ts: ISO 8601 timestamp or a Timestamp object already
@type ts: str or Timestamp
@param sep: one-character separator, placed between the date and time
- @type sep: str
@return: Timestamp object
@rtype: Timestamp
"""
@@ -216,27 +214,23 @@
_items = ('lat', 'lon', 'entity')
@_deprecate_arg('entity', 'globe_item')
- def __init__(self, lat, lon, alt=None, precision=None, globe=None,
- typ='', name='', dim=None, site=None, globe_item=None,
- primary=False):
+ def __init__(self, lat: float, lon: float, alt=None,
+ precision: Optional[float] = None,
+ globe: Optional[str] = None, typ: str = '',
+ name: str = '', dim: Optional[int] = None,
+ site=None, globe_item=None, primary: bool = False):
"""
Represent a geo coordinate.
@param lat: Latitude
- @type lat: float
@param lon: Longitude
- @type lon: float
@param alt: Altitude? TODO FIXME
@param precision: precision
@type precision: float
@param globe: Which globe the point is on
- @type globe: str
@param typ: The type of coordinate point
- @type typ: str
@param name: The name
- @type name: str
@param dim: Dimension (in meters)
- @type dim: int
@param site: The Wikibase site
@type site: pywikibot.site.DataSite
@param globe_item: The Wikibase item for the globe, or the entity URI
@@ -244,7 +238,6 @@
if present.
@type globe_item: pywikibot.ItemPage or str
@param primary: True for a primary set of coordinates
- @type primary: bool
"""
self.lat = lat
self.lon = lon
@@ -576,25 +569,22 @@
precision, before, after, timezone, calendarmodel, site)
@classmethod
- def fromTimestamp(cls, timestamp, precision=14, before=0, after=0,
- timezone=0, calendarmodel=None, site=None):
+ def fromTimestamp(cls, timestamp, precision: Union[int, str] = 14,
+ before: int = 0, after: int = 0,
+ timezone: int = 0, calendarmodel: Optional[str] = None,
+ site=None):
"""
Create a new WbTime object from a pywikibot.Timestamp.
@param timestamp: Timestamp
@type timestamp: pywikibot.Timestamp
@param precision: The unit of the precision of the time.
- @type precision: int or str
@param before: Number of units after the given time it could be, if
uncertain. The unit is given by the precision.
- @type before: int
@param after: Number of units before the given time it could be, if
uncertain. The unit is given by the precision.
- @type after: int
@param timezone: Timezone information in minutes.
- @type timezone: int
@param calendarmodel: URI identifying the calendar model
- @type calendarmodel: str
@param site: The Wikibase site
@type site: pywikibot.site.DataSite
@rtype: pywikibot.WbTime
@@ -655,12 +645,11 @@
return json
@classmethod
- def fromWikibase(cls, wb, site=None):
+ def fromWikibase(cls, wb: dict, site=None):
"""
Create a WbTime from the JSON data given by the Wikibase API.
@param wb: Wikibase JSON
- @type wb: dict
@param site: The Wikibase site
@type site: pywikibot.site.DataSite
@rtype: pywikibot.WbTime
@@ -695,14 +684,13 @@
return site.mw_version < '1.29.0-wmf.2'
@staticmethod
- def _todecimal(value):
+ def _todecimal(value: str):
"""
Convert a string to a Decimal for use in WbQuantity.
None value is returned as is.
@param value: decimal number to convert
- @type value: str
@rtype: Decimal
"""
if isinstance(value, Decimal):
@@ -814,12 +802,11 @@
return json
@classmethod
- def fromWikibase(cls, wb, site=None):
+ def fromWikibase(cls, wb: dict, site=None):
"""
Create a WbQuantity from the JSON data given by the Wikibase API.
@param wb: Wikibase JSON
- @type wb: dict
@param site: The Wikibase site
@type site: pywikibot.site.DataSite
@rtype: pywikibot.WbQuantity
@@ -843,14 +830,12 @@
_items = ('text', 'language')
- def __init__(self, text, language):
+ def __init__(self, text: str, language: str):
"""
Create a new WbMonolingualText object.
@param text: text string
- @type text: str
@param language: language code of the string
- @type language: str
"""
if not text or not language:
raise ValueError('text and language cannot be empty')
@@ -870,12 +855,11 @@
return json
@classmethod
- def fromWikibase(cls, wb):
+ def fromWikibase(cls, wb: dict):
"""
Create a WbMonolingualText from the JSON data given by Wikibase API.
@param wb: Wikibase JSON
- @type wb: dict
@rtype: pywikibot.WbMonolingualText
"""
return cls(wb['text'], wb['language'])
@@ -925,7 +909,7 @@
raise NotImplementedError
@staticmethod
- def _validate(page, data_site, ending, label):
+ def _validate(page, data_site, ending: str, label):
"""
Validate the provided page against general and type specific rules.
@@ -936,7 +920,6 @@
@type data_site: pywikibot.site.APISite
@param ending: Required filetype-like ending in page titles.
E.g. '.map'
- @type ending: str
@param label: Label describing the data type in error messages.
@type site: str
"""
@@ -997,12 +980,11 @@
return self.page.title()
@classmethod
- def fromWikibase(cls, page_name, site):
+ def fromWikibase(cls, page_name: str, site):
"""
Create a _WbDataPage from the JSON data given by the Wikibase API.
@param page_name: page name from Wikibase value
- @type page_name: str
@param site: The Wikibase site
@type site: pywikibot.site.DataSite
@rtype: pywikibot._WbDataPage
@@ -1147,7 +1129,8 @@
@_deprecate_arg('sysop', None)
-def Site(code=None, fam=None, user=None, sysop=None, interface=None, url=None):
+def Site(code: Optional[str] = None, fam=None, user: Optional[str] = None,
+ sysop=None, interface=None, url: Optional[str] = None):
"""A factory method to obtain a Site object.
Site objects are cached and reused by this method.
@@ -1156,17 +1139,14 @@
using the method parameters.
@param code: language code (override config.mylang)
- @type code: str
@param fam: family name or object (override config.family)
@type fam: str or pywikibot.family.Family
@param user: bot user name to use on this site (override config.usernames)
- @type user: str
@param interface: site class or name of class in pywikibot.site
(override config.site_interface)
@type interface: subclass of L{pywikibot.site.BaseSite} or string
@param url: Instead of code and fam, does try to get a Site based on the
URL. Still requires that the family supporting that URL exists.
- @type url: str
@rtype: pywikibot.site.APISite
@raises ValueError: URL and pair of code and family given
@raises ValueError: Invalid interface name
diff --git a/pywikibot/bot_choice.py b/pywikibot/bot_choice.py
index 2242c94..7a00159 100755
--- a/pywikibot/bot_choice.py
+++ b/pywikibot/bot_choice.py
@@ -6,7 +6,9 @@
# Distributed under the terms of the MIT license.
#
import re
+
from textwrap import fill
+from typing import Optional
import pywikibot
@@ -106,13 +108,12 @@
"""An option with a description and shortcut and returning the shortcut."""
- def __init__(self, option: str, shortcut, **kwargs):
+ def __init__(self, option: str, shortcut: str, **kwargs):
"""
Initializer.
@param option: option string
@param shortcut: Shortcut of the option
- @type shortcut: str
"""
super().__init__(**kwargs)
self.option = option
@@ -432,13 +433,12 @@
before_question = True
- def __init__(self, sequence, prefix='', pre=None, post=None, **kwargs):
+ def __init__(self, sequence, prefix='', pre: Optional[str] = None,
+ post: Optional[str] = None, **kwargs):
"""Initializer.
@param pre: Additional comment printed before the list.
- @type pre: str
@param post: Additional comment printed after the list.
- @type post: str
"""
super().__init__(sequence, prefix, **kwargs)
self.pre = pre
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/634285
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I548cb45e6b147ddcda7930c379040482070765ec
Gerrit-Change-Number: 634285
Gerrit-PatchSet: 7
Gerrit-Owner: Udoka <UdokakuUgochukwu(a)gmail.com>
Gerrit-Reviewer: Dr0ptp4kt <abaso(a)wikimedia.org>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged
jenkins-bot has submitted this change. ( https://gerrit.wikimedia.org/r/c/pywikibot/core/+/634238 )
Change subject: [IMPR] remove _http_process() and _enqueue()
......................................................................
[IMPR] remove _http_process() and _enqueue()
Proposal for cleanup.
Clean up http.py avoiding to use single call functions.
_http_process () and _enqueue() have lost their original meaning.
Bug: T265206
Change-Id: I85c2c78fbccd8de1dc6d2a8d7bc89e308d375cd0
---
M pywikibot/comms/http.py
1 file changed, 71 insertions(+), 15 deletions(-)
Approvals:
Xqt: Looks good to me, approved
jenkins-bot: Verified
diff --git a/pywikibot/comms/http.py b/pywikibot/comms/http.py
index 77351e4..fc201d7 100644
--- a/pywikibot/comms/http.py
+++ b/pywikibot/comms/http.py
@@ -283,8 +283,10 @@
return None
+@deprecated(since='20201015', future_warning=True)
def _http_process(session, http_request) -> None:
- """
+ """DEPRECATED.
+
Process an `threadedhttp.HttpRequest` instance.
@param session: Session that will be used to process the `http_request`.
@@ -351,9 +353,11 @@
warning('Http response status {0}'.format(request.data.status_code))
+@deprecated(since='20201015', future_warning=True)
def _enqueue(uri, method='GET', params=None, body=None, headers=None,
data=None, **kwargs):
- """
+ """DEPRECATED.
+
Enqueue non-blocking threaded HTTP request with callback.
Callbacks, including the default error handler if enabled, are run in the
@@ -411,10 +415,7 @@
use_fake_user_agent: Union[bool, str] = False,
data=None, **kwargs):
"""
- Blocking HTTP request.
-
- Note: The callback runs in the HTTP thread, where exceptions are logged
- but are not able to be caught.
+ HTTP request.
See L{requests.Session.request} for parameters.
@@ -422,6 +423,17 @@
@param use_fake_user_agent: Set to True to use fake UA, False to use
pywikibot's UA, str to specify own UA. This behaviour might be
overridden by domain in config.
+
+ @kwarg charset: Either a valid charset (usable for str.decode()) or None
+ to automatically chose the charset from the returned header (defaults
+ to latin-1)
+ @type charset: CodecInfo, str, None
+ @kwarg disable_ssl_certificate_validation: diable SSL Verification
+ @type disable_ssl_certificate_validation: bool
+ @kwarg callback: Method to call once data is fetched
+ @type callback: callable
+ @kwarg callbacks: Methods to call once data is fetched
+ @type callbacks: list of callable
@rtype: L{threadedhttp.HttpRequest}
"""
# body and data parameters both map to the data parameter of
@@ -432,9 +444,15 @@
# Change user agent depending on fake UA settings.
# Set header to new UA if needed.
headers = headers or {}
- # Skip if already specified in request.
- if not headers.get('user-agent', None):
- # Get fake UA exceptions from `fake_user_agent_exceptions` config.
+ headers.update(config.extra_headers.copy() or {})
+
+ if headers.get('user-agent', False):
+ user_agent_format_string = headers.get('user-agent')
+ if not user_agent_format_string or '{' in user_agent_format_string:
+ headers['user-agent'] = user_agent(None, user_agent_format_string)
+ else:
+ # if not already specified,
+ # get fake UA exceptions from `fake_user_agent_exceptions` config.
uri_domain = urlparse(uri).netloc
use_fake_user_agent = config.fake_user_agent_exceptions.get(
uri_domain, use_fake_user_agent)
@@ -444,13 +462,51 @@
elif use_fake_user_agent is True:
headers['user-agent'] = fake_user_agent()
- request = _enqueue(uri, method, params, body, headers, **kwargs)
- # if there's no data in the answer we're in trouble
- assert request._data is not None
- # Run the error handling callback in the callers thread so exceptions
- # may be caught.
+ callbacks = kwargs.pop('callbacks', [])
+ callback = kwargs.pop('callback', None)
+ if callback:
+ callbacks.append(callback)
+
if default_error_handling:
- error_handling_callback(request)
+ callbacks.append(error_handling_callback)
+
+ charset = kwargs.pop('charset', None)
+ request = threadedhttp.HttpRequest(
+ uri, method, params, body, headers, callbacks, charset, **kwargs)
+
+ auth = get_authentication(uri)
+ if auth is not None and len(auth) == 4:
+ if isinstance(requests_oauthlib, ImportError):
+ warn('%s' % requests_oauthlib, ImportWarning)
+ error('OAuth authentication not supported: %s'
+ % requests_oauthlib)
+ auth = None
+ else:
+ auth = requests_oauthlib.OAuth1(*auth)
+
+ timeout = config.socket_timeout
+ ignore_validation = kwargs.pop('disable_ssl_certificate_validation', False)
+
+ try:
+ # Note that the connections are pooled which mean that a future
+ # HTTPS request can succeed even if the certificate is invalid and
+ # verify=True, when a request with verify=False happened before
+ response = session.request(method, uri, params=params, data=body,
+ headers=headers, auth=auth, timeout=timeout,
+ verify=not ignore_validation,
+ **kwargs)
+ except Exception as e:
+ request.data = e
+ else:
+ request.data = response
+ # error_handling_callback is called in HttpRequest data.setter
+
+ # if there's no data in the answer we're in trouble
+ try:
+ request.data
+ except AssertionError as e:
+ raise e
+
return request
# Deprecated parts ############################################################
--
To view, visit https://gerrit.wikimedia.org/r/c/pywikibot/core/+/634238
To unsubscribe, or for help writing mail filters, visit https://gerrit.wikimedia.org/r/settings
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Change-Id: I85c2c78fbccd8de1dc6d2a8d7bc89e308d375cd0
Gerrit-Change-Number: 634238
Gerrit-PatchSet: 5
Gerrit-Owner: Mpaa <mpaa.wiki(a)gmail.com>
Gerrit-Reviewer: Xqt <info(a)gno.de>
Gerrit-Reviewer: jenkins-bot
Gerrit-MessageType: merged