Skip to main content

A module that will help you to generate Pivot Tables base on arbitrary objects

Project description

Pivot Table

Introduction

Given a list of arbitrary objects this module will help you transpose certain selected attributes in order to show them as columns in a table.

Some features:

  • support for Python 2.4 up to 2.7

  • support for Unicode

  • you don’t need to add boilerplate code to fill up missing values

  • both columns and rows will be ordered out of the box

Note: Certain parts of this module (Aggregation and X-Axis definition) are heavily based on Collective.Pivottable written by Luciano Pacheco

An example

Let’s dive into an example so you can see right now if this module may help you or not. Later on, we have full details of every part of it:

Let’s say you have a web service that connects every day to DistroWatch and retrieves a list with the five more popular distros in the Page Hit Ranking. This service gives you the name of the distro, the H.P.D., the tendency and the number of releases each distro has.

An object that can hold such structure might look like this

>>> class Distros(object):
...    def __init__(self, name, h_p_d, tendency, releases):
...        self.name = name
...        self.h_p_d = h_p_d
...        self.tendency = tendency
...        self.releases = releases
...    def __repr__(self):
...        return "<Distro: %s, %d, %s, %d>" % (self.name, self.h_p_d, self.tendency, self.releases)

You retrieve this week’s data and you get

>>> distros = [
...            Distros(u'Ubuntu', 2075, u'+', 13),
...            Distros(u'Mint', 1547, u'=', 12),
...            Distros(u'Fedora', 1460, u'+', 14),
...            Distros(u'Debian', 1143, u'+', 10),
...            Distros(u'OpenSuse', 1135, u'+', 26)
...           ]

With this information you would like to get a table like this (notice that the distros are alphabetically ordered and the name of the object attributes are different):

Distro

Debian

Fedora

Mint

OpenSuse

Ubuntu

Hits per distro

1143

1460

1547

1135

2075

Tendency

+

+

=

+

+

Releases

10

14

12

26

13

You can use this module in this way to get the transposed data (don’t worry, we’ll explain each attribute later)

>>> from pivottable import PivotTable, Sum, GroupBy
>>> pt = PivotTable()
>>> pt.rows = distros
>>> pt.xaxis = "name"
>>> pt.yaxis = [
...         {'attr':u'h_p_d', 'label':u'Hits per distro', 'aggr':Sum},
...         {'attr':u'tendency', 'label':u'Tendency', 'aggr':Sum},
...         {'attr':u'releases', 'label':u'Releases', 'aggr':Sum}]

And finally here’s the result

>>> [a for a in pt.result]
[[u'metric', u'Debian', u'Fedora', u'Mint', u'OpenSuse', u'Ubuntu'], [u'Hits per distro', u'1143', u'1460', u'1547', u'1135', u'2075'], [u'Tendency', u'+', u'+', u'=', u'+', u'+'], [u'Releases', u'10', u'14', u'12', u'26', u'13']]

Or using .next() to get a more clean detail

>>> a = pt.result
>>> a.next()
[u'metric', u'Debian', u'Fedora', u'Mint', u'OpenSuse', u'Ubuntu']
>>> a.next()
[u'Hits per distro', u'1143', u'1460', u'1547', u'1135', u'2075']
>>> a.next()
[u'Tendency', u'+', u'+', u'=', u'+', u'+']
>>> a.next()
[u'Releases', u'10', u'14', u'12', u'26', u'13']

As you might have noticed, the column that brings the name for the measured attribute it’s called metric. In the current release of this library, this name is hardcoded and cannot be changed (although it’s trivial to fix, it might be ready in the next release of this library).

Complete module’s reference

class PivotTable:

This is the module’s main class where you can store the rows you want to pivot and the one that holds the pivotted data. By default it has no __init__ method so it can be initialized by simply calling PivotTable().

Attributes:

  • rows: An attribute where you set the list of objects you want to transpose.

  • result: this is a read only attribute that will return the properly transposed data. In case some required attribute is missing or wrong, calling result will raise a PivotTableError.

  • xaxis: The name of the object attribute that will be use to pivot values. This attr must exist in every object of the list assigned to rows. E.g. if you want a table that, as columns, has all the months for a given year and your object provides such date in a ‘period’ attribute, you should assign ‘period’ as the xaxis.

  • xaxis_format: Callable that will be applied to the pivotted headers. Useful for localization: if your columns will be datetime objects, instead of returning the datetime repr, return a string: e.g: “jan-10”, “ene-10”, etc.

  • xaxis_sort: Boolean flag. Set it to True if you want the pivotted columns to be ordered when building the table. Warning: setting this value as False will not return the columns in the order you append the objects to the list assigned to rows but rather a semi random one (before transposing, a set() operation is applied and afterwards a sorted() operation, in case you set this attribute to True). Default: True

  • yaxis: A list of dictionaries that provides the information required to proper understand your object and what kind of pivot table you need. Provide a dictionary for each attribute in your object you want in the table minus the xaxis attr (that you have already defined in xaxis). Each attribute you define will be a row in the new table except the ones you define as GroupBy attributes (these are going to be use as the pivot keys). The supported keys in each dictionary are:
    • Mandatory:
      • attr: the name of the attr in your object that will provide a value to use in the table

      • label: the name you want to show in the table that represents the attr. Useful for translation purposes

      • aggr: the kind of operation that will be acted upon the submitted attr. See pivottable.Aggregation for more on this.

    • Optional:
      • format: a callable that will be use in ‘attr’ before presenting the information. Useful for localizing number formats (e.g. an attr value is 0.234 but you want to display ‘23.4%’ to american audiences and ‘23,4%’ to german ones). This callable must only accept a “value” parameter.

  • yaxis_order: In case you’re providing more than one attribute as the key to group the data (denoted in yaxis by using ‘aggr’:GroupBy as value:key for the given attributes), you can tell the module in this attribute in what order you want these columns to appear in the final table.

  • headers: This is a read only attribute. After you completed all the required attributes, you can use this attribute to see which are the values for the header row. This same attribute will be the first value in the result attribute (but it will be properly formatted then).

class PivotTableError:

The main error class for this module: will report any errors encountered while pivotting the rows

class Aggregation:

This class works as template for you to define new forms of aggregation you might find useful. At the current release, other than GroupBy and Sum are not defined and has no meaning other than to allow PivotTable to differenciate between keys to transpose and keys as Y-Axis. This is because subtotals and totals are not yet implemented. In a next version of this module these two features will be developed and you will be able to subclass Aggregation and create new forms of Aggregations.

A more complex example

We are ready to work on a more complex example, trying to showcase all PivotTable features.

Imagine you work as a reporting analyst at Capsule Corp. Capsule Corp. has at least two commercial offices in some of the major cities of the world. Your boss requests a report with the results for some key drivers (Customer Base, Churn Rate, Sales and Net Income) for every month in 2010.

To make the scenario a little more complex (and the example shorter) we won’t report every city, every office, every month. Let’s see how PivotTable takes care of filling in the blanks:

Let’s start by creating an object that can hold our data and some formatting functions

>>> from babel import numbers, dates
>>> import datetime
>>> from decimal import Decimal
>>> locale = "en"
>>> class Office(object):
...    def __init__(self, city, office, month, initial_customer_base, sales, cancellations, income):
...        self.city = city
...        self.office = office
...        self.month = month
...        self.initial_customer_base = initial_customer_base
...        self.sales = sales
...        self.cancellations = cancellations
...        self.income = Decimal(income)
...    @property
...    def net_income(self):
...        return self.income-(self.income*Decimal('0.21'))
...    @property
...    def churn(self):
...        try:
...            return float(self.cancellations)/(float(self.initial_customer_base)+float(self.sales))
...        except TypeError:
...            if self.cancellations is None: return 0
...            elif self.sales is None:
...                return float(self.cancellations)/float(self.initial_customer_base)
...
>>> def percent(value):
...     try:
...         return numbers.format_percent(value, '#.##%', locale)
...     except TypeError:
...         return u''
...
>>> def currency(value):
...     try:
...         return numbers.format_currency(value or 0, 'USD', locale=locale)
...     except TypeError:
...         return u''
...
>>> def numerical(value):
...     try:
...         return numbers.format_number(value, locale=locale)
...     except TypeError:
...         return None
...
>>> def format_month(value):
...     try:
...         return dates.format_date(value, 'MMM-yy', locale)
...     except AssertionError:
...         return value
...

And now a list of Office objects

>>> data = [
...     Office(u'West City', u'2nd Office', datetime.date(2010, 1, 1), 12309, 245, 14, 15687697),
...     Office(u'West City', u'3nd Office', datetime.date(2010, 1, 1), 4562, 11, 5, 567332),
...     Office(u'West City', u'1nd Office', datetime.date(2010, 1, 1), 896466, 2344, 156, 16677999),
...     Office(u'West City', u'4nd Office', datetime.date(2010, 1, 1), 976, None, 1, 44780),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 1, 1), 3678, 34, 5, 333241),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 9, 1), 4016, 84, 20, 338930),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 8, 1), 3999, 18, 1, 336808),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 7, 1), 3854, 167, 22, 335697),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 6, 1), 3766, 99, 11, 334243),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 5, 1), 3771, 12, 17, 333796),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 4, 1), 3754, 34, 5, 333574),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 3, 1), 3722, 45, 13, 333370),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 2, 1), 3707, 20, 2, 333466),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 10, 1), 4080, 135, 28, 338257),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 11, 1), 4187, 259, 33, 340268),
...     Office(u'North City', u'1nd Office', datetime.date(2010, 12, 1), 4413, 367, 17, 343352),
...     Office(u'West City', u'2nd Office', datetime.date(2010, 2, 1), 12540, 245, 14, 15688736),
...     Office(u'West City', u'3nd Office', datetime.date(2010, 2, 1), 4568, 11, 5, 567575),
...     Office(u'West City', u'1nd Office', datetime.date(2010, 2, 1), 898654, 2344, 156, 16687999),
...     Office(u'West City', u'4nd Office', datetime.date(2010, 2, 1), 975, None, 1, 44788),
...     Office(u'West City', u'2nd Office', datetime.date(2010, 3, 1), 12771, 245, 14, 15689723),
...     Office(u'West City', u'3nd Office', datetime.date(2010, 3, 1), 4574, 11, 5, 567441),
...     Office(u'West City', u'1nd Office', datetime.date(2010, 3, 1), 900842, 2344, 156, 16689588),
...     Office(u'South City', u'1nd Office', datetime.date(2010, 1, 1), 1238754, 9011, 794, 1177405748),
...     Office(u'South City', u'1nd Office', datetime.date(2010, 3, 1), 1256852, 4028, 893, 1177869032),
...     Office(u'South City', u'1nd Office', datetime.date(2010, 5, 1), 1261837, 7988, 1705, 1179026096),
...     Office(u'South City', u'1nd Office', datetime.date(2010, 7, 1), 1262820, 5555, 1094, 1182109042),
...     Office(u'South City', u'1nd Office', datetime.date(2010, 9, 1), 1266728, 8234, 693, 1184648971),
...     Office(u'South City', u'1nd Office', datetime.date(2010, 11, 1), 1272283, 8887, 917, 1185449009),
...     Office(u'South City', u'1nd Office', datetime.date(2010, 12, 1), 1280253, 8845, 820, 1277349020),
...     Office(u'West City', u'4nd Office', datetime.date(2010, 5, 1), 974, None, 1, 44233),
...     Office(u'West City', u'4nd Office', datetime.date(2010, 6, 1), 973, None, 2, 44356),
...     Office(u'West City', u'4nd Office', datetime.date(2010, 7, 1), 971, None, 1, 44441),
...     Office(u'North City', u'2nd Office', datetime.date(2010, 6, 1), 0, 555, 2, 50001),
...     Office(u'North City', u'2nd Office', datetime.date(2010, 7, 1), 553, 10, None, 52345),
...     Office(u'North City', u'2nd Office', datetime.date(2010, 8, 1), 563, 20, 11, 53400),
...     Office(u'North City', u'2nd Office', datetime.date(2010, 9, 1), 572, 34, 5, 55890),
...     Office(u'North City', u'2nd Office', datetime.date(2010, 10, 1), 601, 256, 25, 77860),
...     Office(u'North City', u'2nd Office', datetime.date(2010, 11, 1), 832, 322, 11, 100543),
...     Office(u'North City', u'2nd Office', datetime.date(2010, 12, 1), 1143, 477, 77, 135789)
...     ]
...

Now, we’ll try to pivot this information. Let’s see step by step.

First, we build a PivotTable instance

>>> pt = PivotTable()

In our object Office, the attribute month is the one we want to transpose into columns

>>> pt.xaxis = "month"

Since it’s a date instance and we want to show a localized string instead of datetime default repr, we apply a formatter function (we defined format_month at the beginning of this exercise)

>>> pt.xaxis_format = format_month

We want the months to be ordered

>>> pt.xaxis_sort = True

Enough about the X-axis, let’s start working with the Y-axis. First we need to tell PivotTable what Office’s attributes should be presented as rows and which ones should be use as Y-axis keys to separate the data. Plus we want to label each metric with a special name and apply some formatter options. Here we have the Y-axis keys

>>> pt.yaxis = [
...         {'attr':'city', 'label':u'City', 'aggr':GroupBy},
...         {'attr':'office', 'label':u'Office', 'aggr':GroupBy}]
...

Now the metrics that will be transformed into rows. As explained before, at the moment, the Aggregate functions (other than GroupBy) bear no meaning and not specific action will be apply when they’re invoked. Nevertheless, we need to defined an Aggregation function that’s not GroupBy in order PivotTable can tell which ones are keys and which ones, metrics

>>> pt.yaxis += [
...         {'attr':'initial_customer_base', 'label':u'Customer Base', 'aggr':Sum, 'format':numerical},
...         {'attr':'churn', 'label':u'Churn Rate', 'aggr':Sum, 'format':percent},
...         {'attr':'sales', 'label':u'Sales', 'aggr':Sum, 'format':numerical},
...         {'attr':'net_income', 'label':u'Net Income', 'aggr':Sum, 'format':currency}]
...

And finally in which order we want the Y-axis keys be presented: first city and then office

>>> pt.yaxis_order = [u'city', u'office']

Now that everything’s configured, let’s add our objects

>>> pt.rows = data

Just to get a preview, we can see which are going to be our headers (previous to formatting)

>>> pt.headers
['city', 'office', u'metric', datetime.date(2010, 1, 1), datetime.date(2010, 2, 1), datetime.date(2010, 3, 1), datetime.date(2010, 4, 1), datetime.date(2010, 5, 1), datetime.date(2010, 6, 1), datetime.date(2010, 7, 1), datetime.date(2010, 8, 1), datetime.date(2010, 9, 1), datetime.date(2010, 10, 1), datetime.date(2010, 11, 1), datetime.date(2010, 12, 1)]

And here’s the final output. We have all the information ordered out of the box both in the Y-axis and the X-axis and with the proper formatting, ready to be incorporated in wherever we need it (for example a template language to build html pages)

>>> for a in pt.result: print(a)
['city', 'office', u'metric', u'Jan-10', u'Feb-10', u'Mar-10', u'Apr-10', u'May-10', u'Jun-10', u'Jul-10', u'Aug-10', u'Sep-10', u'Oct-10', u'Nov-10', u'Dec-10']
[u'North City', u'1nd Office', u'Customer Base', u'3,678', u'3,707', u'3,722', u'3,754', u'3,771', u'3,766', u'3,854', u'3,999', u'4,016', u'4,080', u'4,187', u'4,413']
[u'North City', u'1nd Office', u'Churn Rate', u'0.13%', u'0.05%', u'0.34%', u'0.13%', u'0.45%', u'0.28%', u'0.55%', u'0.02%', u'0.49%', u'0.66%', u'0.74%', u'0.36%']
[u'North City', u'1nd Office', u'Sales', u'34', u'20', u'45', u'34', u'12', u'99', u'167', u'18', u'84', u'135', u'259', u'367']
[u'North City', u'1nd Office', u'Net Income', u'$263,260.39', u'$263,438.14', u'$263,362.30', u'$263,523.46', u'$263,698.84', u'$264,051.97', u'$265,200.63', u'$266,078.32', u'$267,754.70', u'$267,223.03', u'$268,811.72', u'$271,248.08']
[u'North City', u'2nd Office', u'Customer Base', None, None, None, None, None, u'0', u'553', u'563', u'572', u'601', u'832', u'1,143']
[u'North City', u'2nd Office', u'Churn Rate', None, None, None, None, None, u'0.36%', u'0%', u'1.89%', u'0.82%', u'2.92%', u'0.95%', u'4.75%']
[u'North City', u'2nd Office', u'Sales', None, None, None, None, None, u'555', u'10', u'20', u'34', u'256', u'322', u'477']
[u'North City', u'2nd Office', u'Net Income', None, None, None, None, None, u'$39,500.79', u'$41,352.55', u'$42,186.00', u'$44,153.10', u'$61,509.40', u'$79,428.97', u'$107,273.31']
[u'South City', u'1nd Office', u'Customer Base', u'1,238,754', None, u'1,256,852', None, u'1,261,837', None, u'1,262,820', None, u'1,266,728', None, u'1,272,283', u'1,280,253']
[u'South City', u'1nd Office', u'Churn Rate', u'0.06%', None, u'0.07%', None, u'0.13%', None, u'0.09%', None, u'0.05%', None, u'0.07%', u'0.06%']
[u'South City', u'1nd Office', u'Sales', u'9,011', None, u'4,028', None, u'7,988', None, u'5,555', None, u'8,234', None, u'8,887', u'8,845']
[u'South City', u'1nd Office', u'Net Income', u'$930,150,540.92', None, u'$930,516,535.28', None, u'$931,430,615.84', None, u'$933,866,143.18', None, u'$935,872,687.09', None, u'$936,504,717.11', u'$1,009,105,725.80']
[u'West City', u'1nd Office', u'Customer Base', u'896,466', u'898,654', u'900,842', None, None, None, None, None, None, None, None, None]
[u'West City', u'1nd Office', u'Churn Rate', u'0.02%', u'0.02%', u'0.02%', None, None, None, None, None, None, None, None, None]
[u'West City', u'1nd Office', u'Sales', u'2,344', u'2,344', u'2,344', None, None, None, None, None, None, None, None, None]
[u'West City', u'1nd Office', u'Net Income', u'$13,175,619.21', u'$13,183,519.21', u'$13,184,774.52', None, None, None, None, None, None, None, None, None]
[u'West City', u'2nd Office', u'Customer Base', u'12,309', u'12,540', u'12,771', None, None, None, None, None, None, None, None, None]
[u'West City', u'2nd Office', u'Churn Rate', u'0.11%', u'0.11%', u'0.11%', None, None, None, None, None, None, None, None, None]
[u'West City', u'2nd Office', u'Sales', u'245', u'245', u'245', None, None, None, None, None, None, None, None, None]
[u'West City', u'2nd Office', u'Net Income', u'$12,393,280.63', u'$12,394,101.44', u'$12,394,881.17', None, None, None, None, None, None, None, None, None]
[u'West City', u'3nd Office', u'Customer Base', u'4,562', u'4,568', u'4,574', None, None, None, None, None, None, None, None, None]
[u'West City', u'3nd Office', u'Churn Rate', u'0.11%', u'0.11%', u'0.11%', None, None, None, None, None, None, None, None, None]
[u'West City', u'3nd Office', u'Sales', u'11', u'11', u'11', None, None, None, None, None, None, None, None, None]
[u'West City', u'3nd Office', u'Net Income', u'$448,192.28', u'$448,384.25', u'$448,278.39', None, None, None, None, None, None, None, None, None]
[u'West City', u'4nd Office', u'Customer Base', u'976', u'975', None, None, u'974', u'973', u'971', None, None, None, None, None]
[u'West City', u'4nd Office', u'Churn Rate', u'0.1%', u'0.1%', None, None, u'0.1%', u'0.2%', u'0.1%', None, None, None, None, None]
[u'West City', u'4nd Office', u'Sales', None, None, None, None, None, None, None, None, None, None, None, None]
[u'West City', u'4nd Office', u'Net Income', u'$35,376.20', u'$35,382.52', None, None, u'$34,944.07', u'$35,041.24', u'$35,108.39', None, None, None, None, None]

If we change the locale, we will get the information localized for a different culture (of course, PivotTable has nothing to do with it, that’s Babel work)

>>> locale = "es"
>>> a = pt.result
>>> a.next()
['city', 'office', u'metric', u'ene-10', u'feb-10', u'mar-10', u'abr-10', u'may-10', u'jun-10', u'jul-10', u'ago-10', u'sep-10', u'oct-10', u'nov-10', u'dic-10']
>>> a.next()
[u'North City', u'1nd Office', u'Customer Base', u'3.678', u'3.707', u'3.722', u'3.754', u'3.771', u'3.766', u'3.854', u'3.999', u'4.016', u'4.080', u'4.187', u'4.413']
>>> a.next()
[u'North City', u'1nd Office', u'Churn Rate', u'0,13%', u'0,05%', u'0,34%', u'0,13%', u'0,45%', u'0,28%', u'0,55%', u'0,02%', u'0,49%', u'0,66%', u'0,74%', u'0,36%']
>>> a.next()
[u'North City', u'1nd Office', u'Sales', u'34', u'20', u'45', u'34', u'12', u'99', u'167', u'18', u'84', u'135', u'259', u'367']
>>> a.next()
[u'North City', u'1nd Office', u'Net Income', u'US$\xa0263.260,39', u'US$\xa0263.438,14', u'US$\xa0263.362,30', u'US$\xa0263.523,46', u'US$\xa0263.698,84', u'US$\xa0264.051,97', u'US$\xa0265.200,63', u'US$\xa0266.078,32', u'US$\xa0267.754,70', u'US$\xa0267.223,03', u'US$\xa0268.811,72', u'US$\xa0271.248,08']

We can change the Y-axis order too

>>> locale = "en"
>>> pt.yaxis_order = [u'office', u'city']
>>> a = pt.result
>>> a.next()
['office', 'city', u'metric', u'Jan-10', u'Feb-10', u'Mar-10', u'Apr-10', u'May-10', u'Jun-10', u'Jul-10', u'Aug-10', u'Sep-10', u'Oct-10', u'Nov-10', u'Dec-10']
>>> a.next()
[u'1nd Office', u'North City', u'Customer Base', u'3,678', u'3,707', u'3,722', u'3,754', u'3,771', u'3,766', u'3,854', u'3,999', u'4,016', u'4,080', u'4,187', u'4,413']
>>> a.next()
[u'1nd Office', u'North City', u'Churn Rate', u'0.13%', u'0.05%', u'0.34%', u'0.13%', u'0.45%', u'0.28%', u'0.55%', u'0.02%', u'0.49%', u'0.66%', u'0.74%', u'0.36%']
>>> a.next()
[u'1nd Office', u'North City', u'Sales', u'34', u'20', u'45', u'34', u'12', u'99', u'167', u'18', u'84', u'135', u'259', u'367']
>>> a.next()
[u'1nd Office', u'North City', u'Net Income', u'$263,260.39', u'$263,438.14', u'$263,362.30', u'$263,523.46', u'$263,698.84', u'$264,051.97', u'$265,200.63', u'$266,078.32', u'$267,754.70', u'$267,223.03', u'$268,811.72', u'$271,248.08']
>>> a.next()
[u'1nd Office', u'South City', u'Customer Base', u'1,238,754', None, u'1,256,852', None, u'1,261,837', None, u'1,262,820', None, u'1,266,728', None, u'1,272,283', u'1,280,253']

I guess that’s all. Thanks for your patience. If you are interested in more examples you can check the test suite for PivotTable.

Project details


Release history Release notifications | RSS feed

This version

0.8

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

pivottable-0.8-py2.7.egg (16.8 kB view details)

Uploaded Source

pivottable-0.8-py2.6.egg (17.1 kB view details)

Uploaded Source

pivottable-0.8-py2.5.egg (17.0 kB view details)

Uploaded Source

pivottable-0.8-py2.4.egg (17.1 kB view details)

Uploaded Source

File details

Details for the file pivottable-0.8-py2.7.egg.

File metadata

  • Download URL: pivottable-0.8-py2.7.egg
  • Upload date:
  • Size: 16.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for pivottable-0.8-py2.7.egg
Algorithm Hash digest
SHA256 2ec7e712514a7d082f74d62f593571d9aedfbfea634ea23d1e3d7a6c20755aa4
MD5 a6d48836072f82144288e9f3d8d93030
BLAKE2b-256 83875c3a4ee29e10c58565e21c7ab70b96e3b6162dc68cef2c0be81b81c06e09

See more details on using hashes here.

File details

Details for the file pivottable-0.8-py2.6.egg.

File metadata

  • Download URL: pivottable-0.8-py2.6.egg
  • Upload date:
  • Size: 17.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for pivottable-0.8-py2.6.egg
Algorithm Hash digest
SHA256 f2921f0af8574a3eb7bcd52a213b300195344b6a3b51ba83ce6e7386e318eb86
MD5 7eaa41ff28b788c66bdcb25e88e10f55
BLAKE2b-256 fc8b3ab0c95101b6a94b65553c0806689ff9ca1c43656cfb7f3e05ac58e61c8e

See more details on using hashes here.

File details

Details for the file pivottable-0.8-py2.5.egg.

File metadata

  • Download URL: pivottable-0.8-py2.5.egg
  • Upload date:
  • Size: 17.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for pivottable-0.8-py2.5.egg
Algorithm Hash digest
SHA256 96fbba8aad18552e60704f0903311687912b09635670bed44761b6d6e7d791ca
MD5 9c8421dd20d88d6b0c220a2a2e85985f
BLAKE2b-256 74811f52129e6ce0e716205cd54a5e4e1d5f52659baae82dfba94b00015e4c64

See more details on using hashes here.

File details

Details for the file pivottable-0.8-py2.4.egg.

File metadata

  • Download URL: pivottable-0.8-py2.4.egg
  • Upload date:
  • Size: 17.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No

File hashes

Hashes for pivottable-0.8-py2.4.egg
Algorithm Hash digest
SHA256 2e738632f2a0e4bed10cd4574b1323242da1d1924e96f588cc9abca144d6bcde
MD5 36d7433e2a06eabf8bd5304ebf470a2f
BLAKE2b-256 d2996f17ae69e01151f78eac725aa48bc2cdf8d1af27a4d545e98818715ce46b

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page