Skip to content

Commit

Permalink
Merge 1551af0 into e04b9c4
Browse files Browse the repository at this point in the history
  • Loading branch information
achilleas-k committed Jan 17, 2019
2 parents e04b9c4 + 1551af0 commit 4eb031f
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 98 deletions.
4 changes: 2 additions & 2 deletions .travis.yml
Expand Up @@ -77,9 +77,9 @@ install:

script:
- if [[ "${coveralls}" == 1 ]]; then
coverage run --source=nixio setup.py test --addopts "--force-compat -s" && coverage report -m;
coverage run --source=nixio setup.py test --addopts "--nix-compat -s" && coverage report -m;
else
python${pymajor} setup.py test --addopts "--force-compat -s -nauto";
python${pymajor} setup.py test --addopts "--nix-compat -s -nauto";
fi

after_success:
Expand Down
34 changes: 29 additions & 5 deletions conftest.py
@@ -1,6 +1,30 @@
import pytest
import tempfile
from nixio.test.xcompat.compile import maketests


BINDIR = tempfile.mkdtemp(prefix="nixpy-tests-")


def pytest_addoption(parser):
parser.addoption("--force-compat",
action="store_true",
default=False,
help=("Force cross-compatibility tests. "
"Raise error instead of skipping."))
parser.addoption("--nix-compat", action="store_true", default=False,
help=("Run nix compatibility tests "
"(requires NIX library)"))


@pytest.fixture
def bindir(request):
return BINDIR


def pytest_collection_modifyitems(config, items):
if config.getoption("--nix-compat"):
print("Compiling NIX compatibility tests")
maketests(BINDIR)
return
skip_compat = pytest.mark.skip(
reason="Use --nix-compat option to run compatibility tests"
)
for item in items:
if "compatibility" in item.keywords:
item.add_marker(skip_compat)
6 changes: 3 additions & 3 deletions nixio/__init__.py
Expand Up @@ -32,9 +32,9 @@
# version
from .info import VERSION as __version__

__all__ = ("File", "Block", "Group", "DataArray", "DataFrame", "Tag", "MultiTag", "Source",
"Section", "S", "Feature", "Property", "OdmlType",
"SampledDimension", "RangeDimension", "SetDimension",
__all__ = ("File", "Block", "Group", "DataArray", "DataFrame", "Tag",
"MultiTag", "Source", "Section", "S", "Feature", "Property",
"OdmlType", "SampledDimension", "RangeDimension", "SetDimension",
"FileMode", "DataSliceMode", "DataType", "DimensionType",
"LinkType", "Compression")
__author__ = ('Christian Kellner, Adrian Stoewer, Andrey Sobolev, Jan Grewe, '
Expand Down
31 changes: 20 additions & 11 deletions nixio/block.py
Expand Up @@ -14,7 +14,10 @@
import numpy as np
from inspect import isclass
from six import string_types
from collections import OrderedDict # using it for python2.7
try:
from collections.abc import OrderedDict
except ImportError:
from collections import OrderedDict
import sys

from .util import find as finders
Expand Down Expand Up @@ -194,12 +197,13 @@ def create_data_frame(self, name, type_, col_dict=None, col_names=None,
col_dtypes=None, data=None,
compression=Compression.No):

if isinstance(col_dict, dict) and not \
isinstance(col_dict, OrderedDict) and sys.version_info[0] < 3:
if (isinstance(col_dict, dict)
and not isinstance(col_dict, OrderedDict)
and sys.version_info[0] < 3):
raise TypeError("Python 2 users should use name_list "
"or OrderedDict created with LIST and TUPLES"
" to create DataFrames as the order "
"of the columns cannot be maintained in Py2")
"or OrderedDict created with LIST and TUPLES "
"to create DataFrames as the order "
"of the columns cannot be maintained in Py2")

if data is not None:
shape = len(data)
Expand All @@ -210,14 +214,18 @@ def create_data_frame(self, name, type_, col_dict=None, col_names=None,
if col_dict is None:
if col_names is not None:
if col_dtypes is not None:
col_dict = OrderedDict((str(nam), dt)
for nam, dt in zip(col_names, col_dtypes))
col_dict = OrderedDict(
(str(nam), dt)
for nam, dt in zip(col_names, col_dtypes)
)
elif col_dtypes is None and data is not None:
col_dtypes = []
for x in data[0]:
col_dtypes.append(type(x))
col_dict = OrderedDict((str(nam), dt)
for nam, dt in zip(col_names, col_dtypes))
col_dict = OrderedDict(
(str(nam), dt)
for nam, dt in zip(col_names, col_dtypes)
)
else: # col_dtypes is None and data is None
raise (ValueError,
"The data type of each column have to be specified")
Expand All @@ -233,7 +241,8 @@ def create_data_frame(self, name, type_, col_dict=None, col_names=None,
col_dict = OrderedDict(zip(cn, raw_dt_list))

else:
# data is None or type(data[0]) != np.void /data_type doesnt matter
# data is None or type(data[0]) != np.void
# data_type doesnt matter
raise (ValueError,
"No information about column names is provided!")

Expand Down
41 changes: 26 additions & 15 deletions nixio/data_frame.py
Expand Up @@ -2,9 +2,10 @@

from __future__ import (absolute_import, division, print_function)
try:
from collections.abc import Iterable, OrderedDict
from collections.abc import Iterable
except ImportError:
from collections import Iterable, OrderedDict
from collections import Iterable
from collections import OrderedDict
from inspect import isclass
import numpy as np
from .exceptions import OutOfBounds
Expand All @@ -25,9 +26,10 @@ def __init__(self, nixparent, h5group):
self._rows = None

@classmethod
def _create_new(cls, nixparent, h5parent, name, type_, shape, col_dtype, compression):

newentity = super(DataFrame, cls)._create_new(nixparent, h5parent, name, type_)
def _create_new(cls, nixparent, h5parent,
name, type_, shape, col_dtype, compression):
newentity = super(DataFrame, cls)._create_new(nixparent, h5parent,
name, type_)
newentity._h5group.create_dataset("data", (shape, ), col_dtype)
return newentity

Expand All @@ -38,7 +40,8 @@ def append_column(self, column, name, datatype=None):
raise ValueError("Too much entries for column in this dataframe")
if datatype is None:
datatype = DataType.get_dtype(column[0])
if isclass(datatype) and any(issubclass(datatype, st) for st in string_types):
if isclass(datatype) and any(issubclass(datatype, st)
for st in string_types):
datatype = util.vlen_str_dtype
dt_arr = [(n, dty) for n, dty in zip(self.column_names, self.dtype)]
dt_arr.append((name, datatype))
Expand All @@ -56,7 +59,8 @@ def append_column(self, column, name, datatype=None):
self._h5group.create_dataset("data", (self.shape[0],), dt)
self.write_direct(farr)

def append_rows(self, data): # In Python2, the data supplied must be iterable (not np arrays)
def append_rows(self, data):
# In Python2, the data supplied must be iterable (not np arrays)
li_data = []
for d in data:
d = tuple(d)
Expand All @@ -77,7 +81,7 @@ def write_column(self, column, index=None, name=None):
rows[name] = cell
self.write_rows(rows=[rows], index=[i])

# TODO: for read column add a Mode that break down the tuples
# TODO: for read column add a Mode that break down the tuples
def read_columns(self, index=None, name=None, sl=None):
if index is None and name is None:
raise ValueError("Either index or name must not be None")
Expand All @@ -96,10 +100,15 @@ def read_columns(self, index=None, name=None, sl=None):

def write_rows(self, rows, index):
if len(rows) != len(index):
raise IndexError("Length of row changed and index specified do not match")
raise IndexError(
"Number of rows ({}) does not match "
"length of indexes ({})".format(len(rows), len(index))
)
x, = self.shape
if max(index) > (x - 1):
raise OutOfBounds("Row index should not exceed the existing no. of rows")
raise OutOfBounds(
"Row index exceeds the existing number of rows"
)
if len(index) == 1:
rows = tuple(rows[0])
self._write_data(rows, sl=index)
Expand All @@ -118,7 +127,8 @@ def read_rows(self, index):
def write_cell(self, cell, position=None, col_name=None, row_idx=None):
if position is not None:
if len(position) != 2:
raise ValueError('not a position')
raise ValueError("position is invalid: "
"need row and column index")
x, y = position
targeted_row = self.read_rows(x)
targeted_row[y] = cell
Expand Down Expand Up @@ -170,7 +180,7 @@ def write_to_csv(self, filename, mode='w'):
with open(filename, mode, newline='') as csvfile:
dw = csv.DictWriter(csvfile, fieldnames=self.column_names)
dw.writeheader()
di = dict() # this dict make the iter below quicker compared to using self in L172
di = dict()
for n in self.column_names:
n = str(n)
di[n] = list(self[n])
Expand Down Expand Up @@ -199,15 +209,16 @@ def units(self, u):
@property
def columns(self):
if self.units:
cols = [(n, dt, u) for n, dt, u in zip(self.column_names, self.dtype, self.units)]
cols = [(n, dt, u) for n, dt, u in
zip(self.column_names, self.dtype, self.units)]
else:
cols = [(n, dt, None) for n, dt in zip(self.column_names, self.dtype)]
cols = [(n, dt, None) for n, dt in
zip(self.column_names, self.dtype)]
return cols

@property
def column_names(self):
dt = self._h5group.group["data"].dtype
# cn = dt.fields.keys()
return dt.names

@property
Expand Down
39 changes: 22 additions & 17 deletions nixio/test/test_data_frame.py
Expand Up @@ -4,7 +4,10 @@
import os
import numpy as np
from six import string_types
from collections import OrderedDict
try:
from collections.abc import OrderedDict
except ImportError:
from collections import OrderedDict
import sys


Expand All @@ -17,7 +20,7 @@ def setUp(self):
self.file = nix.File.open(self.testfilename, nix.FileMode.Overwrite)
self.block = self.file.create_block("test block", "recordingsession")
di = OrderedDict([('name', np.int64), ('id', str), ('time', float),
('sig1', np.float64), ('sig2', np.int32)])
('sig1', np.float64), ('sig2', np.int32)])
arr = [(1, "a", 20.18, 5.0, 100), (2, 'b', 20.09, 5.5, 101),
(2, 'c', 20.05, 5.1, 100), (1, "d", 20.15, 5.3, 150),
(2, 'e', 20.23, 5.7, 200), (2, 'f', 20.07, 5.2, 300),
Expand All @@ -30,7 +33,8 @@ def setUp(self):
self.df2 = self.block.create_data_frame("other df", "signal2",
data=arr, col_dict=di)
self.df3 = self.block.create_data_frame("reference df", "signal3",
data=other_arr, col_dict=other_di)
data=other_arr,
col_dict=other_di)
self.dtype = self.df1._h5group.group["data"].dtype

def tearDown(self):
Expand All @@ -41,8 +45,8 @@ def create_with_list(self):
arr = np.arange(999).reshape((333, 3))
namelist = np.array(['name', 'id', 'time'])
dtlist = np.array([int, str, float])
new_df = self.blk.create_data_frame('test1', 'for_test',
col_names=namelist, col_dtypes=dtlist, data=arr)
self.blk.create_data_frame('test1', 'for_test', col_names=namelist,
col_dtypes=dtlist, data=arr)

def test_data_frame_eq(self):
assert self.df1 == self.df1
Expand All @@ -57,7 +61,8 @@ def test_create_with_list(self):
namelist = np.array(['name', 'id', 'time', 'sig1', 'sig2'])
dtlist = np.array([np.int64, str, float, np.float64, np.int32])
df_li = self.block.create_data_frame("test_list", "make_of_list",
data=arr, col_names=namelist, col_dtypes=dtlist)
data=arr, col_names=namelist,
col_dtypes=dtlist)
assert df_li.column_names == self.df1.column_names
assert df_li.dtype == self.df1.dtype
for i in df_li[:]:
Expand Down Expand Up @@ -142,19 +147,19 @@ def test_write_cell(self):
def test_append_column(self):
y = np.arange(start=16000, stop=16010, step=1)
self.df1.append_column(y, name='trial_col', datatype=int)
assert self.df1.column_names == \
('name', 'id', 'time', 'sig1', 'sig2', 'trial_col')
assert self.df1.column_names == ('name', 'id', 'time',
'sig1', 'sig2', 'trial_col')
assert len(self.df1.dtype) == 6
k = np.array(self.df1[0:10]["trial_col"], dtype=np.int64)
np.testing.assert_almost_equal(k, y)
# too short coulmn
# too short column
sh_col = np.arange(start=16000, stop=16003, step=1)
self.assertRaises(ValueError, lambda:
self.df1.append_column(sh_col, name='sh_col'))
with self.assertRaises(ValueError):
self.df1.append_column(sh_col, name='sh_col')
# too long column
long = np.arange(start=16000, stop=16500, step=1)
self.assertRaises(ValueError, lambda:
self.df1.append_column(long, name='long'))
with self.assertRaises(ValueError):
self.df1.append_column(long, name='long')

def test_append_rows(self):
# append single row
Expand Down Expand Up @@ -182,12 +187,12 @@ def test_df_shape(self):
# create df with incorrect dimension to see if Error is raised
arr = np.arange(1000).reshape(10, 10, 10)
if sys.version_info[0] == 3:
self.assertRaises(ValueError,
lambda: self.block.create_data_frame('err', 'err',
{'name': np.int64}, data=arr))
with self.assertRaises(ValueError):
self.block.create_data_frame('err', 'err',
{'name': np.int64},
data=arr)

def test_data_type(self):
assert self.df1.dtype[4] == np.int32
assert self.df1.dtype[0] != self.df1.dtype[4]
assert self.df1.dtype[2] == self.df1.dtype[3]

0 comments on commit 4eb031f

Please sign in to comment.