dbt-selly/dbt-env/lib/python3.8/site-packages/agate/computations/percent.py

76 lines
2.5 KiB
Python

#!/usr/bin/env python
from agate.aggregations.has_nulls import HasNulls
from agate.aggregations.sum import Sum
from agate.computations.base import Computation
from agate.data_types import Number
from agate.exceptions import DataTypeError
from agate.warns import warn_null_calculation
class Percent(Computation):
"""
Calculate each values percentage of a total.
:param column_name:
The name of a column containing the :class:`.Number` values.
:param total:
If specified, the total value for each number to be divided into. By
default, the :class:`.Sum` of the values in the column will be used.
"""
def __init__(self, column_name, total=None):
self._column_name = column_name
self._total = total
def get_computed_data_type(self, table):
return Number()
def validate(self, table):
column = table.columns[self._column_name]
if not isinstance(column.data_type, Number):
raise DataTypeError('Percent column must contain Number data.')
if self._total is not None and self._total <= 0:
raise DataTypeError('The total must be a positive number')
# Throw a warning if there are nulls in there
if HasNulls(self._column_name).run(table):
warn_null_calculation(self, column)
def run(self, table):
"""
:returns:
:class:`decimal.Decimal`
"""
# If the user has provided a total, use that
if self._total is not None:
total = self._total
# Otherwise compute the sum of all the values in that column to
# act as our denominator
else:
total = table.aggregate(Sum(self._column_name))
# Raise error if sum is less than or equal to zero
if total <= 0:
raise DataTypeError('The sum of column values must be a positive number')
# Create a list new rows
new_column = []
# Loop through the existing rows
for row in table.rows:
# Pull the value
value = row[self._column_name]
if value is None:
new_column.append(None)
continue
# Try to divide it out of the total
percent = value / total
# And multiply it by 100
percent = percent * 100
# Append the value to the new list
new_column.append(percent)
# Pass out the list
return new_column