docs: def project_views(
              self, projects,
              access='all-access', agent='all-agents', granularity='daily',
              start=None, end=None):
          """
          Get pageview counts for one or more wikimedia projects
          See `<https://wikimedia.org/api/rest_v1/metrics/pageviews/?doc\\
                  #!/Pageviews_data/get_metrics_pageviews_aggregate_project\\
                  _access_agent_granularity_start_end>`_
  
          :Parameters:
              project : list(str)
                  a list of wikimedia projects such as en.wikipedia or commons.wikimedia
              access : str
                  access method (desktop, mobile-web, mobile-app, or by default, all-access)
              agent : str
                  user agent type (spider, user, bot, or by default, all-agents)
              granularity : str
                  the granularity of the timeseries to return (hourly, daily, or monthly)
              end : str|date
                  can be a datetime.date object or string in YYYYMMDDHH format
                  default: today
              start : str|date
                  can be a datetime.date object or string in YYYYMMDDHH format
                  default: 30 days before end date
  
          :Returns:
              a nested dictionary that looks like: {
                  start_date: {
                      project_1: view_count,
                      project_2: view_count,
                      ...
                      project_n: view_count,
                  },
                  ...
                  end_date: {
                      project_1: view_count,
                      project_2: view_count,
                      ...
                      project_n: view_count,
                  }
              }
              The view_count will be None where no data is available, to distinguish from 0
          """
          endDate = end or date.today()
          if type(endDate) is not date:
              endDate = parse_date(end)
  
          startDate = start or endDate - timedelta(30)
          if type(startDate) is not date:
              startDate = parse_date(start)
  
          urls = [
              '/'.join([
                  endpoints['project'], p, access, agent, granularity,
                  format_date(startDate), format_date(endDate),
              ])
              for p in projects
          ]
  
          if granularity == 'hourly':
              increment = timedelta(hours=1)
          elif granularity == 'daily':
              increment = timedelta(days=1)
          elif granularity == 'monthly':
              increment = timedelta(months=1)
  
          outputDays = timestamps_between(startDate, endDate, increment)
          output = defaultdict(dict, {
              day: {p: None for p in projects} for day in outputDays
          })
  
          try:
              results = self.get_concurrent(urls)
              some_data_returned = False
              for result in results:
                  if 'items' in result:
                      some_data_returned = True
                  else:
                      continue
                  for item in result['items']:
                      output[parse_date(item['timestamp'])][item['project']] = item['views']
  
              if not some_data_returned:
                  raise Exception(
                      'The pageview API returned nothing useful at: {}'.format(urls)
                  )
              return output
          except:
              print('ERROR while fetching and parsing ' + str(urls))
              traceback.print_exc()
              raise