"""scholarometer.py - single file Python module for accessing scholarometer.

Note that this module is designed and tested in Python3. No effort is currently
made to support Python 2
"""

# pylama:ignore=E128

# TODO: rest of API

import logging
from urllib.parse import urlunparse, urljoin, quote

import requests  # External dep
from defusedxml.ElementTree import fromstring as xmlparse

# TODO: It would be nice to have an API mock for unit testing


def _log():
    return logging.getLogger('scholarometer')


class Config(object):
    """An instance of this class is an imuutable configuration for API call.

    Currently only our default instance makes sense, so you can just ignore
    this class.
    """

    DEF_SCHEME = 'http'
    DEF_SERVER = 'scholarometer.indiana.edu'
    DEF_ROOT = '/api/'

    def __init__(self, scheme=None, server=None, root=None):
        """Set up the immutable config."""
        self.scheme = scheme or Config.DEF_SCHEME
        self.server = server or Config.DEF_SERVER
        self.root = root or Config.DEF_ROOT
        self.baseurl = urlunparse(
            (self.scheme, self.server, self.root, None, None, None)
        )

    def relative_get(self, path):
        """Create an absolute URL based on path, relative to the API root."""
        url = urljoin(self.baseurl, path)
        _log().info("Perfoming GET %s", url)
        resp = requests.get(url)
        _log().info("[%d]: Got %d bytes in encoding %s (apparent %s)",
            resp.status_code,
            len(resp.content),
            resp.encoding,
            resp.apparent_encoding
        )
        if resp.status_code != 200:
            resp = None
        return resp

Config.DEFAULT_CONFIG = Config()


class Authors(object):
    """Provide the authors portion of the API."""

    def __init__(self, config=None):
        """Init the authors API with given config."""
        self.config = config or Config.DEFAULT_CONFIG

    def _author_parse(self, author):
        if not author:
            return None
        else:
            stats = author.find('statistics')
            return {
                'id': author.attrib['id'],
                'lastupdate': author.attrib['lastupdate'],
                'names': [n.text for n in author.find('names')],
                'article_count': int(stats.find('narticles').text),
                'citation_count': int(stats.find('ncitations').text),
            }

    def get_by_id(self, id):
        """Query author by scholarpedia ID: return a single author or None."""
        resp = self.config.relative_get('authors/id/' + quote(id))
        raw = resp.text if resp and resp.text else None
        if not raw:
            return None
        return self._author_parse(xmlparse(raw))

    def get_by_name(self, name):
        """Query author by name: returns a list of authors."""
        resp = self.config.relative_get('authors/name/' + quote(name))
        raw = resp.text if resp and resp.text else None
        if not raw:
            return []
        authors = xmlparse(raw)
        return [self._author_parse(author) for author in authors]

@@ -1049,29 +1049,92 @@
 EF_ROOT%0A
+%0A
     
-    self.
+def _get_url(self, path, scheme=None, server=None, root=None):%0A        
 baseurl 
@@ -1146,16 +1146,17 @@
 unparse(
+(
 %0A       
@@ -1160,17 +1160,26 @@
         
-(
+scheme or 
 self.sch
@@ -1186,144 +1186,516 @@
 eme,
- self.server, self.root, None, None, None)%0A        )%0A%0A    def relative_get(self, path):%0A        %22%22%22Create an absolute URL based on
+%0A            server or self.server,%0A            root or self.root,%0A            None,%0A            None,%0A            None%0A        ))%0A        return urljoin(baseurl, path)%0A%0A    def _log_response(self, resp):%0A        _log().info(%22%5B%25d%5D: Got %25d bytes in encoding %25s (apparent %25s)%22,%0A            resp.status_code,%0A            len(resp.content),%0A            resp.encoding,%0A            resp.apparent_encoding%0A        )%0A%0A    def relative_get(self, path, root_override=None):%0A        %22%22%22Perform HTTP GET at endpoint
  path
-,
  rel
@@ -1738,34 +1738,46 @@
 l = 
-urljoin(self.baseurl, 
+self._get_url(
 path
+, root=root_override
 )%0A  
@@ -1815,24 +1815,25 @@
 T %25s%22, url)%0A
+%0A
         resp
@@ -1865,82 +1865,42 @@
     
-_log().info(%22%5B%25d%5D: Got %25d bytes in encoding %25s (apparent %25s)%22,%0A   
+self._log_response(resp)%0A%0A
         
  res
@@ -1887,32 +1887,34 @@
 (resp)%0A%0A        
+if
  resp.status_cod
@@ -1906,33 +1906,40 @@
 resp.status_code
-,
+ != 200:
 %0A            len
@@ -1939,98 +1939,339 @@
     
-len(resp.content),%0A            resp.encoding,%0A            resp.apparent_encoding%0A        )
+resp = None%0A        return resp%0A%0A    def relative_post(self, path, root_override=None):%0A        %22%22%22Perform HTTP POST at endpoint path relative to the API root.%22%22%22%0A        url = self._get_url(path, root=root_override)%0A        _log().info(%22Perfoming POST %25s%22, url)%0A%0A        resp = requests.post(url)%0A        self._log_response(resp)%0A
 %0A   
@@ -2348,16 +2348,17 @@
 n resp%0A%0A
+%0A
 Config.D
@@ -3777,8 +3777,135 @@
 uthors%5D%0A
+%0A    def get_articles_by_id(self, id):%0A        %22%22%22Return all articles published by the given author id.%22%22%22%0A        return None%0A

Refactor for POST