Skip to content

Commit

Permalink
Merge pull request #115 from Crunch-io/full-test-coverage
Browse files Browse the repository at this point in the history
Full test coverage
  • Loading branch information
slobodan-ilic authored Nov 2, 2018
2 parents adcb2c5 + 713f4f8 commit cd7be98
Show file tree
Hide file tree
Showing 16 changed files with 281 additions and 89 deletions.
5 changes: 5 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
graft src
graft tests
graft docs
prune docs/build

include README.md
include LICENSE

include .coveragerc
include tox.ini .travis.yml
include *.md
include *.txt
include *.yaml
include Makefile

recursive-exclude * __pycache__ *.py[cod]
6 changes: 5 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
MAKE = make
PYTHON = python
SETUP = $(PYTHON) ./setup.py

.PHONY: clean cleandocs docs opendocs
.PHONY: clean cleandocs docs opendocs sdist

help:
@echo "Usage: \`make <target>' where <target> is one or more of"
Expand All @@ -26,3 +27,6 @@ docs:

opendocs:
open docs/build/html/index.html

sdist:
$(SETUP) sdist
4 changes: 2 additions & 2 deletions src/cr/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# See http://peak.telecommunity.com/DevCenter/setuptools#namespace-packages
try:
try: # pragma: no cover
__import__('pkg_resources').declare_namespace(__name__)
except ImportError:
except ImportError: # pragma: no cover
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
29 changes: 21 additions & 8 deletions src/cr/cube/crunch_cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
from __future__ import division

import json
import numpy as np
import warnings

import numpy as np
from scipy.stats import norm
from scipy.stats.contingency import expected_freq

Expand Down Expand Up @@ -74,13 +74,26 @@ def __init__(self, response):
).format(type(response)))

def __repr__(self):
text = '\n' + str(type(self))
text += '\nName: {}'.format(self.name)
text += '\nType: {}'.format(' x '.join(self.dim_types))
text += '\n\nSlices:'
for slice_ in self.slices:
text += str(slice_)
return text
"""Provide text representation suitable for working at console.
Falls back to a default repr on exception, such as might occur in
unit tests where object need not otherwise be provided with all
instance variable values.
"""
try:
dimensionality = ' x '.join(dt.name for dt in self.dim_types)
slice_reprs = (
'\n'.join(
'slices[%d]: %s' % (idx, repr(s))
for idx, s in enumerate(self.slices)
)
)
return (
"%s(name='%s', dim_types='%s')\n%s" %
(type(self).__name__, self.name, dimensionality, slice_reprs)
)
except Exception:
return super(CrunchCube, self).__repr__()

def as_array(self, include_missing=False, weighted=True, adjusted=False,
include_transforms_for_dims=None, prune=False, margin=False):
Expand Down
49 changes: 30 additions & 19 deletions src/cr/cube/cube_slice.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

from __future__ import division

from functools import partial
import warnings
from functools import partial

import numpy as np
from tabulate import tabulate

from cr.cube.enum import DIMENSION_TYPE as DT
from cr.cube.measures.scale_means import ScaleMeans
from cr.cube.util import lazyproperty, compress_pruned, memoize
from cr.cube.util import compress_pruned, lazyproperty, memoize


class CubeSlice(object):
Expand Down Expand Up @@ -61,23 +62,33 @@ def __getattr__(self, attr):
return cube_attr

def __repr__(self):
text = '\n\n' + str(type(self))
text += '\nName: {}'.format(
self.table_name if self.table_name else self.name)
text += '\nType: {}'.format(' x '.join(self.dim_types))
text += '\nDimensions: {}'.format(
' x '.join([dim.name for dim in self.dimensions]))
labels = self.labels()
headers = labels[1] if len(labels) > 1 else ['N']
tbl = self.as_array()
if len(tbl.shape) <= 1:
tbl = tbl[:, None]
body = tabulate(
[[lbl] + lst for lbl, lst in zip(labels[0], tbl.tolist())],
headers=headers
)
text += '\n' + body
return text
"""Provide text representation suitable for working at console.
Falls back to a default repr on exception, such as might occur in
unit tests where object need not otherwise be provided with all
instance variable values.
"""
try:
name = self.table_name if self.table_name else self.name
dimensionality = ' x '.join(dt.name for dt in self.dim_types)
dim_names = ' x '.join(d.name for d in self.dimensions)
labels = self.labels()
headers = labels[1] if len(labels) > 1 else ['N']
tbl = (
self.as_array()
if len(self.as_array().shape) > 1
else self.as_array()[:, None]
)
body = tabulate(
[[lbl] + lst for lbl, lst in zip(labels[0], tbl.tolist())],
headers=headers
)
return (
"%s(name='%s', dim_types='%s', dims='%s')\n%s" %
(type(self).__name__, name, dimensionality, dim_names, body)
)
except Exception:
return super(CubeSlice, self).__repr__()

@lazyproperty
def ca_main_axis(self):
Expand Down
27 changes: 17 additions & 10 deletions src/cr/cube/enum.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

"""Enumerated sets related to cubes."""

from cr.cube.util import lazyproperty


class _DimensionType(object):
"""Member of the DIMENSION_TYPE enumeration."""
Expand All @@ -15,29 +17,34 @@ def __repr__(self):
def __str__(self):
return 'DIMENSION_TYPE.%s' % self._name

@lazyproperty
def name(self):
"""str like 'CA_CAT' for this dimension type."""
return self._name


class DIMENSION_TYPE(object):
"""Enumerated values representing the various types of dimension."""

# ---member definitions---
BINNED_NUMERIC = _DimensionType('BINNED_NUMERIC')
CATEGORICAL = _DimensionType('CATEGORICAL')
CATEGORICAL_ARRAY = _DimensionType('CATEGORICAL_ARRAY')
CAT = _DimensionType('CAT')
CA_CAT = _DimensionType('CA_CAT')
CA_SUBVAR = _DimensionType('CA_SUBVAR')
DATETIME = _DimensionType('DATETIME')
LOGICAL = _DimensionType('LOGICAL')
MR_CAT = _DimensionType('MR_CAT')
MULTIPLE_RESPONSE = _DimensionType('MULTIPLE_RESPONSE')
MR_SUBVAR = _DimensionType('MR_SUBVAR')
TEXT = _DimensionType('TEXT')

# ---aliases---
CA = CATEGORICAL_ARRAY
CAT = CATEGORICAL
CAT_ARRAY = CATEGORICAL_ARRAY
CA_SUBVAR = CATEGORICAL_ARRAY
MR = MULTIPLE_RESPONSE
CA = CA_SUBVAR
CATEGORICAL = CAT
CATEGORICAL_ARRAY = CA_SUBVAR
CAT_ARRAY = CA_SUBVAR
MR = MR_SUBVAR
MR_SELECTIONS = MR_CAT
MR_SUBVAR = MULTIPLE_RESPONSE
MULTIPLE_RESPONSE = MR_SUBVAR

# ---subsets---
ARRAY_TYPES = frozenset((CATEGORICAL_ARRAY, MULTIPLE_RESPONSE))
ARRAY_TYPES = frozenset((CA_SUBVAR, MR_SUBVAR))
11 changes: 5 additions & 6 deletions src/cr/cube/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@

import collections
import functools
import json
import os

import numpy as np

try:
from itertools import ifilterfalse
except ImportError:
except ImportError: # pragma: no cover
from itertools import filterfalse as ifilterfalse

import json
import os


def compress_pruned(table):
"""Compress table based on pruning mask.
Expand Down Expand Up @@ -172,7 +172,6 @@ def lru_cache(maxsize=100):
Cache performance statistics stored in f.hits and f.misses.
Clear the cache with f.clear().
http://en.wikipedia.org/wiki/Cache_algorithms#Least_Recently_Used
"""
maxqueue = maxsize * 10

Expand Down Expand Up @@ -229,7 +228,7 @@ def wrapper(*args, **kwds):

return result

def clear():
def clear(): # pragma: no cover
cache.clear()
queue.clear()
refcount.clear()
Expand Down
13 changes: 13 additions & 0 deletions tests/integration/test_crunch_cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@

class DescribeIntegratedCrunchCube(object):

def it_provides_a_console_friendly_repr_for_a_cube(self):
cube = CrunchCube(CAT_X_CAT)
repr_ = repr(cube)
assert repr_ == (
'CrunchCube(name=\'v4\', dim_types=\'CAT x CAT\')\n'
'slices[0]: CubeSlice(name=\'v4\', dim_types=\'CAT x CAT\', dims'
'=\'v4 x v7\')\n'
' C E\n'
'-- --- ---\n'
'B 5 2\n'
'C 5 3'
)

def it_provides_access_to_its_dimensions(self, dimensions_fixture):
cube_response, expected_dimension_types = dimensions_fixture
cube = CrunchCube(cube_response)
Expand Down
19 changes: 18 additions & 1 deletion tests/integration/test_cube_slice.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,23 @@
from cr.cube.crunch_cube import CrunchCube

from .fixtures import CAT_X_CAT_PRUNING_HS
from .fixtures import CAT_X_CAT, CAT_X_CAT_PRUNING_HS


class DescribeIntegratedCrunchCube(object):

def it_provides_a_console_friendly_repr_for_a_slice(self):
cube = CrunchCube(CAT_X_CAT)
slice_ = cube.slices[0]

repr_ = repr(slice_)

assert repr_ == (
"CubeSlice(name='v4', dim_types='CAT x CAT', dims='v4 x v7')\n"
" C E\n"
"-- --- ---\n"
"B 5 2\n"
"C 5 3"
)


def test_labels_with_hs_and_pruning():
Expand Down
21 changes: 8 additions & 13 deletions tests/integration/test_index.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from unittest import TestCase
# encoding: utf-8

import numpy as np

from unittest import TestCase

from cr.cube.crunch_cube import CrunchCube

from .fixtures import CAT_X_MR_SIMPLE
from .fixtures import PETS_X_PETS
from .fixtures import SELECTED_CROSSTAB_4
from .fixtures import CAT_X_MR_X_MR
from .fixtures import CA_ITEMS_X_CA_CAT_X_CAT
from .fixtures import (
CAT_X_MR_SIMPLE, CA_ITEMS_X_CA_CAT_X_CAT, PETS_X_PETS,
SELECTED_CROSSTAB_4
)


class TestIndex(TestCase):
Expand Down Expand Up @@ -43,13 +45,6 @@ def test_mr_x_mr_index(self):
actual = cube.index()
np.testing.assert_almost_equal(actual, expected)

def test_cat_mr_x_mr_index(self):
self.skipTest('not yet implemented')
cube = CrunchCube(CAT_X_MR_X_MR)
expected = np.array([])
actual = cube.index()
np.testing.assert_almost_equal(actual, expected)

def test_ca_items_x_ca_cat_x_cat_index(self):
cube = CrunchCube(CA_ITEMS_X_CA_CAT_X_CAT)

Expand Down
14 changes: 5 additions & 9 deletions tests/unit/test_crunch_cube.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@

class DescribeCrunchCube(object):

def it_provides_a_default_repr(self):
cube = CrunchCube({})
repr_ = repr(cube)
assert repr_.startswith('<cr.cube.crunch_cube.CrunchCube object at 0x')

def it_provides_access_to_its_dimensions(
self, _all_dimensions_prop_, all_dimensions_,
apparent_dimensions_):
Expand Down Expand Up @@ -166,15 +171,6 @@ def adjust_fixture(self, request):
dimension_types, axis_cases = request.param
return dimension_types, axis_cases

@pytest.fixture(params=[
# ---0 - CA---
((DT.CA, DT.CAT),
(0, None, (0, 1))),
])
def adjust_raises_fixture(self, request):
dimension_types, axis_cases = request.param
return dimension_types, axis_cases

@pytest.fixture(params=[
# ---0 - CA---
((DT.CA, DT.CAT),
Expand Down
Loading

0 comments on commit cd7be98

Please sign in to comment.