Exemple #1
0
def error_handling_callback(request):
    """
    Raise exceptions and log alerts.

    @param request: Request that has completed
    @type request: L{threadedhttp.HttpRequest}
    """
    # TODO: do some error correcting stuff
    if isinstance(request.data, requests.exceptions.SSLError):
        if SSL_CERT_VERIFY_FAILED_MSG in str(request.data):
            raise FatalServerError(str(request.data))

    # if all else fails
    if isinstance(request.data, Exception):
        raise request.data

    if request.status == 504:
        raise Server504Error("Server %s timed out" % request.hostname)

    if request.status == 414:
        raise Server414Error('Too long GET request')

    # HTTP status 207 is also a success status for Webdav FINDPROP,
    # used by the version module.
    if request.status not in (200, 207):
        warning('Http response status {0}'.format(request.data.status_code))
Exemple #2
0
def error_handling_callback(request):
    """
    Raise exceptions and log alerts.

    @param request: Request that has completed
    @type request: L{threadedhttp.HttpRequest}
    """
    # TODO: do some error correcting stuff
    if isinstance(request.data, requests.exceptions.SSLError):
        if SSL_CERT_VERIFY_FAILED_MSG in str(request.data):
            raise FatalServerError(str(request.data))

    if request.status_code == 504:
        raise Server504Error('Server {} timed out'.format(
            urlparse(request.url).netloc))

    if request.status_code == 414:
        raise Server414Error('Too long GET request')

    if isinstance(request.data, Exception):
        error('An error occurred for uri ' + request.url)
        raise request.data from None

    # HTTP status 207 is also a success status for Webdav FINDPROP,
    # used by the version module.
    if request.status_code not in (200, 207):
        warning('Http response status {}'.format(request.status_code))
Exemple #3
0
def _code_fam_from_url(url: str, name: Optional[str] = None):
    """Set url to cache and get code and family from cache.

    Site helper method.
    @param url: The site URL to get code and family
    @param name: A family name used by AutoFamily
    """
    matched_sites = []
    # Iterate through all families and look, which does apply to
    # the given URL
    for fam in config.family_files:
        family = Family.load(fam)
        code = family.from_url(url)
        if code is not None:
            matched_sites.append((code, family))

    if not matched_sites:
        if not name:  # create a name from url
            name = urlparse(url).netloc.split('.')[-2]
            name = removesuffix(name, 'wiki')
        family = AutoFamily(name, url)
        matched_sites.append((family.code, family))

    if len(matched_sites) > 1:
        warning('Found multiple matches for URL "{}": {} (use first)'.format(
            url, ', '.join(str(s) for s in matched_sites)))
    return matched_sites[0]
Exemple #4
0
def error_handling_callback(response):
    """
    Raise exceptions and log alerts.

    :param response: Response returned by Session.request().
    :type response: :py:obj:`requests.Response`
    """
    # TODO: do some error correcting stuff
    if isinstance(response, requests.exceptions.SSLError):
        if SSL_CERT_VERIFY_FAILED_MSG in str(response):
            raise FatalServerError(str(response))

    if isinstance(response, Exception):
        with suppress(Exception):
            # request exception may contain response and request attribute
            error('An error occurred for uri ' + response.request.url)
        raise response from None

    if response.status_code == HTTPStatus.GATEWAY_TIMEOUT:
        raise Server504Error('Server {} timed out'.format(
            urlparse(response.url).netloc))

    if response.status_code == HTTPStatus.REQUEST_URI_TOO_LONG:
        raise Server414Error('Too long GET request')

    # TODO: shall it raise? this might break some code, TBC
    # response.raise_for_status()

    # HTTP status 207 is also a success status for Webdav FINDPROP,
    # used by the version module.
    if response.status_code not in (HTTPStatus.OK, HTTPStatus.MULTI_STATUS):
        warning('Http response status {}'.format(response.status_code))
Exemple #5
0
def _code_fam_from_url(url):
    """Set url to cache and get code and family from cache.

    Site helper method.
    @param url: The site URL to get code and family
    @type url: str
    @raises SiteDefinitionError: Unknown URL
    """
    if url not in _url_cache:
        matched_sites = []
        # Iterate through all families and look, which does apply to
        # the given URL
        for fam in config.family_files:
            if fam == 'test':  # test_family.py is deprecated
                continue
            family = Family.load(fam)
            code = family.from_url(url)
            if code is not None:
                matched_sites.append((code, family))

        if not matched_sites:
            # TODO: As soon as AutoFamily is ready, try and use an
            #       AutoFamily
            raise SiteDefinitionError("Unknown URL '{0}'.".format(url))
        if len(matched_sites) > 1:
            warning('Found multiple matches for URL "{0}": {1} (use first)'
                    .format(url, ', '.join(str(s) for s in matched_sites)))
        _url_cache[url] = matched_sites[0]
    return _url_cache[url]
Exemple #6
0
def error_handling_callback(request):
    """
    Raise exceptions and log alerts.

    @param request: Request that has completed
    @type request: L{threadedhttp.HttpRequest}
    """
    # TODO: do some error correcting stuff
    if isinstance(request.data, requests.exceptions.SSLError):
        if SSL_CERT_VERIFY_FAILED_MSG in str(request.data):
            raise FatalServerError(str(request.data))

    # if all else fails
    if isinstance(request.data, Exception):
        raise request.data

    if request.status == 504:
        raise Server504Error("Server %s timed out" % request.hostname)

    if request.status == 414:
        raise Server414Error('Too long GET request')

    # HTTP status 207 is also a success status for Webdav FINDPROP,
    # used by the version module.
    if request.status not in (200, 207):
        warning('Http response status {0}'.format(request.data.status_code))
Exemple #7
0
def _code_fam_from_url(url):
    """Set url to cache and get code and family from cache.

    Site helper method.
    @param url: The site URL to get code and family
    @type url: str
    @raises SiteDefinitionError: Unknown URL
    """
    if url not in _url_cache:
        matched_sites = []
        # Iterate through all families and look, which does apply to
        # the given URL
        for fam in config.family_files:
            family = Family.load(fam)
            code = family.from_url(url)
            if code is not None:
                matched_sites.append((code, family))

        if not matched_sites:
            # TODO: As soon as AutoFamily is ready, try and use an
            #       AutoFamily
            raise SiteDefinitionError("Unknown URL '{0}'.".format(url))
        if len(matched_sites) > 1:
            warning('Found multiple matches for URL "{0}": {1} (use first)'
                    .format(url, ', '.join(str(s) for s in matched_sites)))
        _url_cache[url] = matched_sites[0]
    return _url_cache[url]
Exemple #8
0
    def _require_errors(site: DataSite) -> bool:
        """
        Check if Wikibase site is so old it requires error bounds to be given.

        If no site item is supplied it raises a warning and returns True.

        @param site: The Wikibase site
        """
        if not site:
            warning(
                "WbQuantity now expects a 'site' parameter. This is needed to "
                'ensure correct handling of error bounds.')
            return False
        return site.mw_version < '1.29.0-wmf.2'
Exemple #9
0
    def _require_errors(site):
        """
        Check if the Wikibase site is so old it requires error bounds to be given.

        If no site item is supplied it raises a warning and returns True.

        @param site: The Wikibase site
        @type site: pywikibot.site.DataSite
        @rtype: bool
        """
        if not site:
            warning(
                "WbQuantity now expects a 'site' parameter. This is needed to "
                "ensure correct handling of error bounds.")
            return False
        return MediaWikiVersion(site.version()) < MediaWikiVersion('1.29.0-wmf.2')
Exemple #10
0
    def _require_errors(site):
        """
        Check if the Wikibase site is so old it requires error bounds to be given.

        If no site item is supplied it raises a warning and returns True.

        @param site: The Wikibase site
        @type site: pywikibot.site.DataSite
        @rtype: bool
        """
        if not site:
            warning(
                "WbQuantity now expects a 'site' parameter. This is needed to "
                "ensure correct handling of error bounds.")
            return False
        return MediaWikiVersion(site.version()) < MediaWikiVersion('1.29.0-wmf.2')
Exemple #11
0
def error_handling_callback(response):
    """
    Raise exceptions and log alerts.

    @param response: Response returned by Session.request().
    @type response: L{requests.Response}
    """
    # TODO: do some error correcting stuff
    if isinstance(response, requests.exceptions.SSLError):
        if SSL_CERT_VERIFY_FAILED_MSG in str(response):
            raise FatalServerError(str(response))

    if isinstance(response, Exception):
        with suppress(Exception):
            # request.data exception may contain response and request attribute
            error('An error occurred for uri ' + response.request.url)
        raise response from None

    if response.status_code == 504:
        raise Server504Error('Server {} timed out'.format(
            urlparse(response.url).netloc))

    if response.status_code == 414:
        raise Server414Error('Too long GET request')

    # TODO: shall it raise? this might break some code, TBC
    # response.raise_for_status()

    # HTTP status 207 is also a success status for Webdav FINDPROP,
    # used by the version module.
    if response.status_code not in (200, 207):
        warning('Http response status {}'.format(response.status_code))

    if isinstance(response.encoding, UnicodeDecodeError):
        error('An error occurred for uri {}: '
              'no encoding detected!'.format(response.request.url))
        raise response.encoding from None
Exemple #12
0
def _code_fam_from_url(url: str):
    """Set url to cache and get code and family from cache.

    Site helper method.
    @param url: The site URL to get code and family
    @raises pywikibot.exceptions.SiteDefinitionError: Unknown URL
    """
    matched_sites = []
    # Iterate through all families and look, which does apply to
    # the given URL
    for fam in config.family_files:
        family = Family.load(fam)
        code = family.from_url(url)
        if code is not None:
            matched_sites.append((code, family))

    if not matched_sites:
        # TODO: As soon as AutoFamily is ready, try and use an
        #       AutoFamily
        raise SiteDefinitionError("Unknown URL '{}'.".format(url))
    if len(matched_sites) > 1:
        warning('Found multiple matches for URL "{}": {} (use first)'
                .format(url, ', '.join(str(s) for s in matched_sites)))
    return matched_sites[0]
Exemple #13
0
def Site(code=None, fam=None, user=None, sysop=None, interface=None, url=None):
    """A factory method to obtain a Site object.

    Site objects are cached and reused by this method.

    By default rely on config settings. These defaults may all be overridden
    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 Family
    @param user: bot user name to use on this site (override config.usernames)
    @type user: str
    @param sysop: sysop user to use on this site (override config.sysopnames)
    @type sysop: 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
    @raises SiteDefinitionError: Unknown URL
    """
    _logger = 'wiki'

    if url:
        # Either code and fam or only url
        if code or fam:
            raise ValueError(
                'URL to the wiki OR a pair of code and family name '
                'should be provided')
        code, fam = _code_fam_from_url(url)
    else:
        # Fallback to config defaults
        code = code or config.mylang
        fam = fam or config.family

        if not isinstance(fam, Family):
            fam = Family.load(fam)

    interface = interface or fam.interface(code)

    # config.usernames is initialised with a defaultdict for each family name
    family_name = str(fam)

    code_to_user = config.usernames['*'].copy()
    code_to_user.update(config.usernames[family_name])
    user = user or code_to_user.get(code) or code_to_user.get('*')

    code_to_sysop = config.sysopnames['*'].copy()
    code_to_sysop.update(config.sysopnames[family_name])
    sysop = sysop or code_to_sysop.get(code) or code_to_sysop.get('*')

    if not isinstance(interface, type):
        # If it isn't a class, assume it is a string
        if PY2:  # Must not be unicode in Python 2
            interface = str(interface)
        try:
            tmp = __import__('pywikibot.site', fromlist=[interface])
        except ImportError:
            raise ValueError('Invalid interface name: {0}'.format(interface))
        else:
            interface = getattr(tmp, interface)

    if not issubclass(interface, BaseSite):
        warning('Site called with interface=%s' % interface.__name__)

    user = normalize_username(user)
    key = '%s:%s:%s:%s' % (interface.__name__, fam, code, user)
    if key not in _sites or not isinstance(_sites[key], interface):
        _sites[key] = interface(code=code, fam=fam, user=user, sysop=sysop)
        debug("Instantiated %s object '%s'"
              % (interface.__name__, _sites[key]), _logger)

        if _sites[key].code != code:
            warn('Site %s instantiated using different code "%s"'
                 % (_sites[key], code), UserWarning, 2)

    return _sites[key]
Exemple #14
0
for _key, _val in _glv.items():
    if isinstance(_val, dict):
        if isinstance(_val, collections.defaultdict):
            _uc[_key] = collections.defaultdict(dict)
        else:
            _uc[_key] = {}
        if len(_val) > 0:
            _uc[_key].update(_val)
    else:
        _uc[_key] = _val

# Get the user files
_thislevel = 0
if __no_user_config:
    if __no_user_config != '2':
        warning('Skipping loading of user-config.py.')
    _fns = []
else:
    _fns = [os.path.join(_base_dir, "user-config.py")]
for _filename in _fns:
    _thislevel += 1
    if os.path.exists(_filename):
        _filestatus = os.stat(_filename)
        _filemode = _filestatus[0]
        _fileuid = _filestatus[4]
        if OSWIN32 or _fileuid in [os.getuid(), 0]:
            if OSWIN32 or _filemode & 0o02 == 0:
                with open(_filename, 'rb') as f:
                    exec(compile(f.read(), _filename, 'exec'), _uc)
            else:
                warning("Skipped '%(fn)s': writeable by others." %
Exemple #15
0
def Site(code=None, fam=None, user=None, sysop=None, interface=None, url=None):
    """A factory method to obtain a Site object.

    Site objects are cached and reused by this method.

    By default rely on config settings. These defaults may all be overridden
    using the method parameters.

    @param code: language code (override config.mylang)
    @type code: string
    @param fam: family name or object (override config.family)
    @type fam: string or Family
    @param user: bot user name to use on this site (override config.usernames)
    @type user: unicode
    @param sysop: sysop user to use on this site (override config.sysopnames)
    @type sysop: unicode
    @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: string
    @rtype: pywikibot.site.APISite

    """
    # Either code and fam or only url
    if url and (code or fam):
        raise ValueError('URL to the wiki OR a pair of code and family name '
                         'should be provided')
    _logger = "wiki"

    if url:
        if url not in _url_cache:
            matched_sites = []
            # Iterate through all families and look, which does apply to
            # the given URL
            for fam in config.family_files:
                family = Family.load(fam)
                code = family.from_url(url)
                if code is not None:
                    matched_sites += [(code, family)]

            if matched_sites:
                if len(matched_sites) > 1:
                    warning(
                        'Found multiple matches for URL "{0}": {1} (use first)'
                        .format(url, ', '.join(str(s) for s in matched_sites)))
                _url_cache[url] = matched_sites[0]
            else:
                # TODO: As soon as AutoFamily is ready, try and use an
                #       AutoFamily
                _url_cache[url] = None

        cached = _url_cache[url]
        if cached:
            code = cached[0]
            fam = cached[1]
        else:
            raise SiteDefinitionError("Unknown URL '{0}'.".format(url))
    else:
        # Fallback to config defaults
        code = code or config.mylang
        fam = fam or config.family

        if not isinstance(fam, Family):
            fam = Family.load(fam)

    interface = interface or fam.interface(code)

    # config.usernames is initialised with a defaultdict for each family name
    family_name = str(fam)

    code_to_user = config.usernames['*'].copy()
    code_to_user.update(config.usernames[family_name])
    user = user or code_to_user.get(code) or code_to_user.get('*')

    code_to_sysop = config.sysopnames['*'].copy()
    code_to_sysop.update(config.sysopnames[family_name])
    sysop = sysop or code_to_sysop.get(code) or code_to_sysop.get('*')

    if not isinstance(interface, type):
        # If it isnt a class, assume it is a string
        try:
            tmp = __import__('pywikibot.site', fromlist=[interface])
            interface = getattr(tmp, interface)
        except ImportError:
            raise ValueError('Invalid interface name: {0}'.format(interface))

    if not issubclass(interface, BaseSite):
        warning('Site called with interface=%s' % interface.__name__)

    user = normalize_username(user)
    key = '%s:%s:%s:%s' % (interface.__name__, fam, code, user)
    if key not in _sites or not isinstance(_sites[key], interface):
        _sites[key] = interface(code=code, fam=fam, user=user, sysop=sysop)
        debug(u"Instantiated %s object '%s'"
              % (interface.__name__, _sites[key]), _logger)

        if _sites[key].code != code:
            warn('Site %s instantiated using different code "%s"'
                 % (_sites[key], code), UserWarning, 2)

    return _sites[key]
Exemple #16
0
# System-level and User-level changes.
# Store current variables and their types.
_public_globals = {
    _key: _val for _key, _val in globals().items()
    if _key[0] != '_' and _key not in _imports}

# Create an environment for user-config.py which is
# a deep copy of the core config settings, so that
# we can detect modified config items easily.
_exec_globals = copy.deepcopy(_public_globals)

# Get the user files
if __no_user_config:
    if __no_user_config != '2':
        warning('Skipping loading of user-config.py.')
else:
    _filename = os.path.join(base_dir, 'user-config.py')
    if os.path.exists(_filename):
        _filestatus = os.stat(_filename)
        _filemode = _filestatus[0]
        _fileuid = _filestatus[4]
        if OSWIN32 or _fileuid in [os.getuid(), 0]:
            if OSWIN32 or _filemode & 0o02 == 0:
                with open(_filename, 'rb') as f:
                    exec(compile(f.read(), _filename, 'exec'), _exec_globals)
            else:
                warning("Skipped '%(fn)s': writeable by others."
                        % {'fn': _filename})
        else:
            warning("Skipped '%(fn)s': owned by someone else."
Exemple #17
0
# Store current variables and their types.
_public_globals = {
    _key: _val
    for _key, _val in globals().items()
    if _key[0] != '_' and _key not in _imports
}

# Create an environment for user-config.py which is
# a deep copy of the core config settings, so that
# we can detect modified config items easily.
_exec_globals = copy.deepcopy(_public_globals)

# Get the user files
if __no_user_config:
    if __no_user_config != '2':
        warning('Skipping loading of user-config.py.')
else:
    _filename = os.path.join(base_dir, 'user-config.py')

    def read_user_config():
        with open(_filename, 'rb') as f:
            exec(compile(f.read(), _filename, 'exec'), _exec_globals)

    if os.path.exists(_filename):
        _filestatus = os.stat(_filename)
        _filemode = _filestatus[0]
        _fileuid = _filestatus[4]
        if OSWIN32 or _fileuid in [os.getuid(), 0]:
            if OSWIN32 or _filemode & 0o02 == 0:
                read_user_config()
            else:
Exemple #18
0
for _key, _val in _glv.items():
    if isinstance(_val, dict):
        if isinstance(_val, collections.defaultdict):
            _uc[_key] = collections.defaultdict(dict)
        else:
            _uc[_key] = {}
        if len(_val) > 0:
            _uc[_key].update(_val)
    else:
        _uc[_key] = _val

# Get the user files
_thislevel = 0
if __no_user_config:
    if __no_user_config != "2":
        warning("Skipping loading of user-config.py.")
    _fns = []
else:
    _fns = [os.path.join(_base_dir, "user-config.py")]
for _filename in _fns:
    _thislevel += 1
    if os.path.exists(_filename):
        _filestatus = os.stat(_filename)
        _filemode = _filestatus[0]
        _fileuid = _filestatus[4]
        if OSWIN32 or _fileuid in [os.getuid(), 0]:
            if OSWIN32 or _filemode & 0o02 == 0:
                with open(_filename, "rb") as f:
                    exec(compile(f.read(), _filename, "exec"), _uc)
            else:
                warning("Skipped '%(fn)s': writeable by others." % {"fn": _filename})
Exemple #19
0
def Site(code: Optional[str] = None,
         fam=None,
         user: Optional[str] = None,
         *,
         interface=None,
         url: Optional[str] = None) -> Union[APISite, DataSite, ClosedSite]:
    """A factory method to obtain a Site object.

    Site objects are cached and reused by this method.

    By default rely on config settings. These defaults may all be overridden
    using the method parameters.

    @param code: language code (override config.mylang)
        code may also be a sitename like 'wikipedia:test'
    @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)
    @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.
    @raises ValueError: URL and pair of code and family given
    @raises ValueError: Invalid interface name
    """
    _logger = 'wiki'

    if url:
        # Either code and fam or url with optional fam for AutoFamily name
        if code:
            raise ValueError(
                'URL to the wiki OR a pair of code and family name '
                'should be provided')
        code, fam = _code_fam_from_url(url, fam)
    elif code and ':' in code:
        if fam:
            raise ValueError('sitename OR a pair of code and family name '
                             'should be provided')
        fam, _, code = code.partition(':')
    else:
        # Fallback to config defaults
        code = code or config.mylang
        fam = fam or config.family

    if not isinstance(fam, Family):
        fam = Family.load(fam)

    interface = interface or fam.interface(code)

    # config.usernames is initialised with a defaultdict for each family name
    family_name = str(fam)

    code_to_user = {}
    if '*' in config.usernames:  # T253127: usernames is a defaultdict
        code_to_user = config.usernames['*'].copy()
    code_to_user.update(config.usernames[family_name])
    user = user or code_to_user.get(code) or code_to_user.get('*')

    if not isinstance(interface, type):
        # If it isn't a class, assume it is a string
        try:
            tmp = __import__('pywikibot.site', fromlist=[interface])
        except ImportError:
            raise ValueError('Invalid interface name: {0}'.format(interface))
        else:
            interface = getattr(tmp, interface)

    if not issubclass(interface, BaseSite):
        warning('Site called with interface=%s' % interface.__name__)

    user = normalize_username(user)
    key = '%s:%s:%s:%s' % (interface.__name__, fam, code, user)
    if key not in _sites or not isinstance(_sites[key], interface):
        _sites[key] = interface(code=code, fam=fam, user=user)
        debug(
            "Instantiated %s object '%s'" % (interface.__name__, _sites[key]),
            _logger)

        if _sites[key].code != code:
            warn(
                'Site %s instantiated using different code "%s"' %
                (_sites[key], code), UserWarning, 2)

    return _sites[key]
Exemple #20
0
)
from pywikibot.logging import critical, debug, error, log, warning
from pywikibot.tools import deprecate_arg, issue_deprecation_warning, PY2

import pywikibot.version

# The error message for failed SSL certificate verification
# 'certificate verify failed' is a commonly detectable string
SSL_CERT_VERIFY_FAILED_MSG = 'certificate verify failed'

_logger = "comm.http"

if (isinstance(config.socket_timeout, tuple) and
        StrictVersion(requests.__version__) < StrictVersion('2.4.0')):
    warning('The configured timeout is a tuple but requests does not '
            'support a tuple as a timeout. It uses the lower of the '
            'two.')
    config.socket_timeout = min(config.socket_timeout)

cookie_jar = cookielib.LWPCookieJar(
    config.datafilepath('pywikibot.lwp'))
try:
    cookie_jar.load()
except (IOError, cookielib.LoadError):
    debug('Loading cookies failed.', _logger)
else:
    debug('Loaded cookies from file.', _logger)

session = requests.Session()
session.cookies = cookie_jar
Exemple #21
0
def Site(code=None, fam=None, user=None, sysop=None, interface=None, url=None):
    """A factory method to obtain a Site object.

    Site objects are cached and reused by this method.

    By default rely on config settings. These defaults may all be overridden
    using the method parameters.

    @param code: language code (override config.mylang)
    @type code: string
    @param fam: family name or object (override config.family)
    @type fam: string or Family
    @param user: bot user name to use on this site (override config.usernames)
    @type user: unicode
    @param sysop: sysop user to use on this site (override config.sysopnames)
    @type sysop: unicode
    @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: string
    @rtype: pywikibot.site.APISite

    """
    # Either code and fam or only url
    if url and (code or fam):
        raise ValueError('URL to the wiki OR a pair of code and family name '
                         'should be provided')
    _logger = "wiki"

    if url:
        if url not in _url_cache:
            matched_sites = []
            # Iterate through all families and look, which does apply to
            # the given URL
            for fam in config.family_files:
                family = Family.load(fam)
                code = family.from_url(url)
                if code is not None:
                    matched_sites += [(code, family)]

            if matched_sites:
                if len(matched_sites) > 1:
                    warning(
                        'Found multiple matches for URL "{0}": {1} (use first)'
                        .format(url, ', '.join(str(s) for s in matched_sites)))
                _url_cache[url] = matched_sites[0]
            else:
                # TODO: As soon as AutoFamily is ready, try and use an
                #       AutoFamily
                _url_cache[url] = None

        cached = _url_cache[url]
        if cached:
            code = cached[0]
            fam = cached[1]
        else:
            raise SiteDefinitionError("Unknown URL '{0}'.".format(url))
    else:
        # Fallback to config defaults
        code = code or config.mylang
        fam = fam or config.family

        if not isinstance(fam, Family):
            fam = Family.load(fam)

    interface = interface or fam.interface(code)

    # config.usernames is initialised with a defaultdict for each family name
    family_name = str(fam)

    code_to_user = config.usernames['*'].copy()
    code_to_user.update(config.usernames[family_name])
    user = user or code_to_user.get(code) or code_to_user.get('*')

    code_to_sysop = config.sysopnames['*'].copy()
    code_to_sysop.update(config.sysopnames[family_name])
    sysop = sysop or code_to_sysop.get(code) or code_to_sysop.get('*')

    if not isinstance(interface, type):
        # If it isnt a class, assume it is a string
        try:
            tmp = __import__('pywikibot.site', fromlist=[interface])
            interface = getattr(tmp, interface)
        except ImportError:
            raise ValueError('Invalid interface name: {0}'.format(interface))

    if not issubclass(interface, BaseSite):
        warning('Site called with interface=%s' % interface.__name__)

    user = normalize_username(user)
    key = '%s:%s:%s:%s' % (interface.__name__, fam, code, user)
    if key not in _sites or not isinstance(_sites[key], interface):
        _sites[key] = interface(code=code, fam=fam, user=user, sysop=sysop)
        debug(
            u"Instantiated %s object '%s'" % (interface.__name__, _sites[key]),
            _logger)

        if _sites[key].code != code:
            warn(
                'Site %s instantiated using different code "%s"' %
                (_sites[key], code), UserWarning, 2)

    return _sites[key]
Exemple #22
0
    PY2,
    StringTypes,
)

import pywikibot.version

# The error message for failed SSL certificate verification
# 'certificate verify failed' is a commonly detectable string
SSL_CERT_VERIFY_FAILED_MSG = 'certificate verify failed'

_logger = "comm.http"

if (isinstance(config.socket_timeout, tuple)
        and StrictVersion(requests.__version__) < StrictVersion('2.4.0')):
    warning('The configured timeout is a tuple but requests does not '
            'support a tuple as a timeout. It uses the lower of the '
            'two.')
    config.socket_timeout = min(config.socket_timeout)

cookie_jar = cookielib.LWPCookieJar(config.datafilepath('pywikibot.lwp'))
try:
    cookie_jar.load()
except (IOError, cookielib.LoadError):
    debug('Loading cookies failed.', _logger)
else:
    debug('Loaded cookies from file.', _logger)

session = requests.Session()
session.cookies = cookie_jar

Exemple #23
0
    if _key[0] != '_' and _key not in _imports
}

# Create an environment for user-config.py which is
# a deep copy of the core config settings, so that
# we can detect modified config items easily.
_exec_globals = copy.deepcopy(_public_globals)

# Always try to get the user files
_filename = os.path.join(base_dir, 'user-config.py')
if os.path.exists(_filename):
    _filestatus = os.stat(_filename)
    _filemode = _filestatus[0]
    _fileuid = _filestatus[4]
    if not OSWIN32 and _fileuid not in [os.getuid(), 0]:
        warning('Skipped {fn!r}: owned by someone else.'.format(fn=_filename))
    elif OSWIN32 or _filemode & 0o02 == 0:
        with open(_filename, 'rb') as f:
            exec(compile(f.read(), _filename, 'exec'), _exec_globals)
    else:
        warning('Skipped {fn!r}: writeable by others.'.format(fn=_filename))
elif __no_user_config and __no_user_config != '2':
    warning('user-config.py cannot be loaded.')


class _DifferentTypeError(UserWarning, TypeError):
    """An error when the required type doesn't match the actual type."""
    def __init__(self, name, actual_type, allowed_types):
        super().__init__('Configuration variable "{}" is defined as "{}" in '
                         'your user-config.py but expected "{}".'.format(
                             name, actual_type.__name__,
Exemple #24
0
for _key, _val in _glv.items():
    if isinstance(_val, dict):
        if isinstance(_val, collections.defaultdict):
            _uc[_key] = collections.defaultdict(dict)
        else:
            _uc[_key] = {}
        if len(_val) > 0:
            _uc[_key].update(_val)
    else:
        _uc[_key] = _val

# Get the user files
_thislevel = 0
if __no_user_config:
    if __no_user_config != '2':
        warning('Skipping loading of user-config.py.')
    _fns = []
else:
    _fns = [os.path.join(_base_dir, "user-config.py")]
for _filename in _fns:
    _thislevel += 1
    if os.path.exists(_filename):
        _filestatus = os.stat(_filename)
        _filemode = _filestatus[0]
        _fileuid = _filestatus[4]
        if OSWIN32 or _fileuid in [os.getuid(), 0]:
            if OSWIN32 or _filemode & 0o02 == 0:
                with open(_filename, 'rb') as f:
                    exec(compile(f.read(), _filename, 'exec'), _uc)
            else:
                warning("Skipped '{fn!s}': writeable by others.".format(**{'fn': _filename}))
Exemple #25
0
for _key, _val in _glv.items():
    if isinstance(_val, dict):
        if isinstance(_val, collections.defaultdict):
            _uc[_key] = collections.defaultdict(dict)
        else:
            _uc[_key] = {}
        if len(_val) > 0:
            _uc[_key].update(_val)
    else:
        _uc[_key] = _val

# Get the user files
_thislevel = 0
if _no_user_config:
    if _no_user_config != '2':
        warning('Skipping loading of user-config.py.')
    _fns = []
else:
    _fns = [os.path.join(_base_dir, "user-config.py")]
for _filename in _fns:
    _thislevel += 1
    if os.path.exists(_filename):
        _filestatus = os.stat(_filename)
        _filemode = _filestatus[0]
        _fileuid = _filestatus[4]
        if sys.platform == 'win32' or _fileuid in [os.getuid(), 0]:
            if sys.platform == 'win32' or _filemode & 0o02 == 0:
                with open(_filename, 'rb') as f:
                    exec(compile(f.read(), _filename, 'exec'), _uc)
            else:
                warning("Skipped '%(fn)s': writeable by others."
Exemple #26
0
def Site(code: Optional[str] = None,
         fam: Union[str, 'Family', None] = None,
         user: Optional[str] = None,
         *,
         interface: Union[str, 'BaseSite', None] = None,
         url: Optional[str] = None) -> BaseSite:
    """A factory method to obtain a Site object.

    Site objects are cached and reused by this method.

    By default rely on config settings. These defaults may all be overridden
    using the method parameters.

    Creating the default site using config.mylang and config.family::

        site = pywikibot.Site()

    Override default site code::

        site = pywikibot.Site('fr')

    Override default family::

        site = pywikibot.Site(family='wikisource')

    Setting a specific site::

        site = pywikibot.Site('fr', 'wikisource')

    which is equal to::

        site = pywikibot.Site('wikisource:fr')

    :Note: An already created site is cached an a new variable points to
        the same object if interface, family, code and user are equal:

    >>> import pywikibot
    >>> site_1 = pywikibot.Site('wikisource:fr')
    >>> site_2 = pywikibot.Site('fr', 'wikisource')
    >>> site_1 is site_2
    True
    >>> site_1
    APISite("fr", "wikisource")

    ``APISite`` is the default interface. Refer :py:obj:`pywikibot.site` for
    other interface types.

    **Never create a site object via interface class directly.**
    Always use this factory method.

    :param code: language code (override config.mylang)
        code may also be a sitename like 'wikipedia:test'
    :param fam: family name or object (override config.family)
    :param user: bot user name to use on this site (override config.usernames)
    :param interface: site class or name of class in :py:obj:`pywikibot.site`
        (override config.site_interface)
    :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.
    :raises ValueError: URL and pair of code and family given
    :raises ValueError: Invalid interface name
    :raises ValueError: Missing Site code
    :raises ValueError: Missing Site family
    """
    _logger = 'wiki'

    if url:
        # Either code and fam or url with optional fam for AutoFamily name
        if code:
            raise ValueError(
                'URL to the wiki OR a pair of code and family name '
                'should be provided')
        code, fam = _code_fam_from_url(url, fam)
    elif code and ':' in code:
        if fam:
            raise ValueError('sitename OR a pair of code and family name '
                             'should be provided')
        fam, _, code = code.partition(':')
    else:
        # Fallback to config defaults
        code = code or _config.mylang
        fam = fam or _config.family

    if not (code and fam):
        raise ValueError(
            'Missing Site {}'.format('code' if not code else 'family'))

    if not isinstance(fam, Family):
        fam = Family.load(fam)

    interface = interface or fam.interface(code)

    # config.usernames is initialised with a defaultdict for each family name
    family_name = str(fam)

    code_to_user = {}
    if '*' in _config.usernames:  # T253127: usernames is a defaultdict
        code_to_user = _config.usernames['*'].copy()
    code_to_user.update(_config.usernames[family_name])
    user = user or code_to_user.get(code) or code_to_user.get('*')

    if not isinstance(interface, type):
        # If it isn't a class, assume it is a string
        try:
            tmp = __import__('pywikibot.site', fromlist=[interface])
        except ImportError:
            raise ValueError('Invalid interface name: {}'.format(interface))
        else:
            interface = getattr(tmp, interface)

    if not issubclass(interface, BaseSite):
        warning('Site called with interface={}'.format(interface.__name__))

    user = normalize_username(user)
    key = '{}:{}:{}:{}'.format(interface.__name__, fam, code, user)
    if key not in _sites or not isinstance(_sites[key], interface):
        _sites[key] = interface(code=code, fam=fam, user=user)
        debug(
            "Instantiated {} object '{}'".format(interface.__name__,
                                                 _sites[key]), _logger)

        if _sites[key].code != code:
            warn(
                'Site {} instantiated using different code "{}"'.format(
                    _sites[key], code), UserWarning, 2)

    return _sites[key]
Exemple #27
0
def Site(code=None, fam=None, user=None, sysop=None, interface=None, url=None):
    """A factory method to obtain a Site object.

    Site objects are cached and reused by this method.

    By default rely on config settings. These defaults may all be overridden
    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 Family
    @param user: bot user name to use on this site (override config.usernames)
    @type user: str
    @param sysop: sysop user to use on this site (override config.sysopnames)
    @type sysop: 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
    @raises SiteDefinitionError: Unknown URL
    """
    _logger = 'wiki'

    if url:
        # Either code and fam or only url
        if code or fam:
            raise ValueError(
                'URL to the wiki OR a pair of code and family name '
                'should be provided')
        code, fam = _code_fam_from_url(url)
    else:
        # Fallback to config defaults
        code = code or config.mylang
        fam = fam or config.family

        if not isinstance(fam, Family):
            fam = Family.load(fam)

    interface = interface or fam.interface(code)

    # config.usernames is initialised with a defaultdict for each family name
    family_name = str(fam)

    code_to_user = config.usernames['*'].copy()
    code_to_user.update(config.usernames[family_name])
    user = user or code_to_user.get(code) or code_to_user.get('*')

    code_to_sysop = config.sysopnames['*'].copy()
    code_to_sysop.update(config.sysopnames[family_name])
    sysop = sysop or code_to_sysop.get(code) or code_to_sysop.get('*')

    if not isinstance(interface, type):
        # If it isn't a class, assume it is a string
        if PY2:  # Must not be unicode in Python 2
            interface = str(interface)
        try:
            tmp = __import__('pywikibot.site', fromlist=[interface])
        except ImportError:
            raise ValueError('Invalid interface name: {0}'.format(interface))
        else:
            interface = getattr(tmp, interface)

    if not issubclass(interface, BaseSite):
        warning('Site called with interface=%s' % interface.__name__)

    user = normalize_username(user)
    key = '%s:%s:%s:%s' % (interface.__name__, fam, code, user)
    if key not in _sites or not isinstance(_sites[key], interface):
        _sites[key] = interface(code=code, fam=fam, user=user, sysop=sysop)
        debug("Instantiated %s object '%s'"
              % (interface.__name__, _sites[key]), _logger)

        if _sites[key].code != code:
            warn('Site %s instantiated using different code "%s"'
                 % (_sites[key], code), UserWarning, 2)

    return _sites[key]