Source code for pypiview

# -*- python -*-
# -*- coding: utf-8 -*-
#
#  This file is part of the easydev software
#
#  Copyright (c) 2011-2014
#
#  File author(s): Thomas Cokelaer <cokelaer@gmail.com>
#
#  Distributed under the GPLv3 License.
#  See accompanying file LICENSE.txt or copy at
#      http://www.gnu.org/licenses/gpl-3.0.html
#
#  Website: https://www.assembla.com/spaces/pyeasydev/wiki
#  Documentation: http://packages.python.org/easydev
#
##############################################################################
# $:Id $
"""Utilities to lookup into pypi stats.


.. warning:: requires pandas and vanity packages
"""
import datetime
import sys
import vanity
import pandas as pd
import pylab


__all__ = ["PYPIView"]


[docs]class PYPIView(object): """Plot number of downloads versus time of a PYPI package. .. plot:: :include-source: :width: 80% from pypiview import PYPIView p = PYPIView(["requests"], verbose=False) p.plot(logy=True) The attribute :attr:`df` contains the dataframe with all results. The attribute :attr:`tss` contains the individual TimeSeries for each package as returned by :meth:`get_data_one_package`. """ def __init__(self, packages, verbose=True): """.. rubric:: Constructor :param packages: list of packages or single package :param bool verbose: print some information. """ if isinstance(packages, (str)): packages = [packages] self.verbose = verbose self.tss = [] for package in packages: print("Downloading data for {0} package".format(package)) ts = self.get_data_one_package(package) self.tss.append(ts.to_frame()) self.df = pd.concat(self.tss) self.df = self.df.sort_index() self.df = self.df.fillna(method='bfill').fillna(0) if self.verbose: print(self.df)
[docs] def get_data_one_package(self, package): """Return the data for one package :param str pacakge: a single package name :return: a Pandas time series. """ downloads = [] times = [] for data, metadata in vanity.get_release_info([package]): if len(data) == 0: continue data = data[0] if "upload_time" in data.keys() and \ "downloads" in data.keys(): dtime = data['upload_time'] tt = dtime.timetuple() times.append([tt[0], tt[1], tt[2]]) download = data['downloads'] downloads.append(download) df = pd.Series(downloads, [datetime.datetime(*x) for x in times], name=package) df = df.sort_index() return df
[docs] def plot(self, lw=2, fontsize=16, marker='o', logy=False): """plot the number of downloads The data used is the data stored in the :attr:`df` attribute. :param int lw: width of the curves :param int fontsize: fontsize used in titles :param marker: :param bool logy: set y-axis to logarithmic scale #. first plot shows the cumulative downloads #. second plot shows the individual downloads .. plot:: from pypiview import PYPIView p = PYPIView("requests", verbose=False) p.plot() """ times = self.df.index fig, (ax1, ax2) = pylab.subplots(2,1, figsize=(12,8)) fig.autofmt_xdate() for this in self.df.columns: data = self.df[this].values ax1.plot(times, data, lw=lw, marker='o') ax2.plot(times, pylab.cumsum(data), lw=lw, marker='o') ax1.legend(list(self.df.columns), loc="upper left") ax1.set_title("Downloads of each release", fontsize=fontsize) ax1.grid(True) #ax1.xticks(rotation=45, fontsize=fontsize) ax2.legend(list(self.df.columns), loc="upper left") ax2.set_title("Cumulative downloads of each release", fontsize=fontsize) ax2.grid(True) #ax2.xticks(rotation=45, fontsize=fontsize) try: pylab.tight_layout() except: pass if logy: ax1.semilogy() ax2.semilogy()
def Help(): print("T.C, Aug 2014\n") print("Usage: \n") print("\tpypiview [pkgnames]\n") print("[pkgnames] is a list of one or several packages to be found on pypi\n") print("Other options are\n") print("You can also add --verbose option") print("plots can be tuned with --fontsize <number>") print("plots can be tuned with --lw <number> , to set the line width of the curves") print("plots can be tuned with --logy optoin to set y-scale to a log scale") print("\nExamples:\n") print(" pypiview requests --verbose --logy --lw 2 --fontsize 16\n") print(" pypiview setuptools distribute --verbose --logy --lw 2 --fontsize 16\n") def main(show=True): """The main executable""" args = sys.argv if "--help" in args: Help() return # could use argparse but there are just a few parameters. if len(args)<2: Help() return if "--verbose" in args: verbose = True index = args.index('--verbose') args.pop(index) else: verbose = False if "--logy" in args: logy = True index = args.index('--logy') args.pop(index) else: logy = False if "--fontsize" in args: index = args.index("--fontsize") fontsize = args[index+1] args.pop(index) args.pop(index) else: fontsize = 16 if "--lw" in args: index = args.index("--lw") lw = args[index+1] args.pop(index) args.pop(index) else: lw = 2 print(args[1:]) p = PYPIView(args[1:], verbose=verbose) p.plot(lw=lw, fontsize=fontsize, logy=logy) if show: pylab.show() if __name__ == "__main__": main()