Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: Roundtrip Tests #4

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build/
dist/
pyEDF.egg-info/
*.pyc
*.*~
27 changes: 27 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
pyEDF
=====

Python package to read from and write EEG data to European Data Format
files. It is implemented in pure Python with very limited dependencies
on external packages.

See also
--------

- https://github.com/holgern/pyedflib
- https://github.com/MNE-tools/MNE-python

Assuming a standard Python environment is installed on your machine
(including pip), pyEDF can be installed from PyPI:

::

python -m pip install --user --upgrade pyEDF

For the current pre-release version, you can install from GitHub:

::

python -m pip install --user --upgrade git+https://github.com/robertoostenveld/pyEDF.git

Dependencies should be handled automatically by pip.
339 changes: 201 additions & 138 deletions EDF.py → pyEDF/EDF.py

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions pyEDF/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
__version__ = 0.1
from .EDF import EDFWriter, EDFReader
6 changes: 6 additions & 0 deletions pyEDF/tests/config_vars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018 Phillip Alday <me@phillipalday.com>
# License: BSD (3-clause)

import os.path as op
data_path = op.expanduser('~/edf_data')
9 changes: 9 additions & 0 deletions pyEDF/tests/test_edfreader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018 Phillip Alday <me@phillipalday.com>
# License: BSD (3-clause)
"""Tests for reading EDF files"""

from nose.tools import assert_dict_equal, assert_raises

from config_vars import data_path
from os.path import join
9 changes: 9 additions & 0 deletions pyEDF/tests/test_edfwriter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018 Phillip Alday <me@phillipalday.com>
# License: BSD (3-clause)
"""Tests for writing EDF files"""

from nose.tools import assert_dict_equal, assert_raises

from config_vars import data_path
from os.path import join
87 changes: 87 additions & 0 deletions pyEDF/tests/test_roundtrip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# -*- coding: utf-8 -*-
# Copyright (C) 2018 Phillip Alday <me@phillipalday.com>
# License: BSD (3-clause)
"""Round Trip Data IO tests.

Note that these tests are *slow*. The entirety of each file is effectively
read in 3 times and written to disk once.
"""

from nose.tools import assert_dict_equal, assert_true, assert_sequence_equal
import numpy as np

from config_vars import data_path
from os.path import join

import pyEDF

try:
# Python 2
from os import tempnam, unlink
except ImportError:
# Python 3
from os import unlink
from tempfile import NamedTemporaryFile

tempnam = lambda: NamedTemporaryFile(delete=False).name

def _roundtrip(edf_file):
edfin = pyEDF.EDFReader(edf_file)

fout = tempnam()
edfout = pyEDF.EDFWriter(fout)

header = edfin.readHeader()
edfout.writeHeader(header)

meas_info = header[0]
for i in range(int(meas_info['n_records'])):
edfout.writeBlock(edfin.readBlock(i))

edfin.close()
edfout.close()

original = pyEDF.EDFReader(edf_file)
copy = pyEDF.EDFReader(fout)

copy_header = copy.readHeader()

assert_dict_equal(header[0], copy_header[0])
for key in header[1]:
assert_sequence_equal(list(header[1][key]), list(copy_header[1][key]))

for i in range(int(meas_info['n_records'])):
# although this is floating point, it's not really numerics.
# it's just comparing copies of the same data, so exact equality
# should be a doable goal.
for ch_orig, ch_copy in zip(original.readBlock(i), copy.readBlock(i)):
assert_sequence_equal(list(ch_orig), list(ch_copy))

unlink(fout)

def test_roundtrip_0601_s():
'''Roundtrip of file 0601_s.edf'''
# this file seems to have bad physical_min values
_roundtrip(join(data_path, '0601_s.edf'))

def test_roundtrip_composition1_0s_to_1892s_fs20_15channels_tap127():
'''Roundtrip of file composition1_0s_to_1892s_fs20_15channels_tap127.edf'''
_roundtrip(join(data_path, 'composition1_0s_to_1892s_fs20_15channels_tap127.edf'))


def test_roundtrip_NY394_VisualLoc_R1():
'''Roundtrip of file NY394_VisualLoc_R1.edf'''
_roundtrip(join(data_path, 'NY394_VisualLoc_R1.edf'))


def test_roundtrip_shhs1_200001():
'''Roundtrip of file shhs1-200001.edf'''
_roundtrip(join(data_path, 'shhs1-200001.edf'))

def test_roundtrip_testAlphaIR20170321_0():
'''Roundtrip of file testAlphaIR20170321-0.edf'''
_roundtrip(join(data_path, 'testAlphaIR20170321-0.edf'))

def test_roundtrip_test_generator():
'''Roundtrip of file test_generator.edf'''
_roundtrip(join(data_path, 'test_generator.edf'))
101 changes: 101 additions & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#! /usr/bin/env python
#
# Copyright (C) 2018 Phillip Alday <me@phillipalday.com>
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.

# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.



import os
from os import path as op

from setuptools import setup

PACKAGE_NAME = 'pyEDF'

# get the version (don't import mne here, so dependencies are not needed)
version = None
with open(os.path.join(PACKAGE_NAME, '__init__.py'), 'r') as fid:
for line in (line.strip() for line in fid):
if line.startswith('__version__'):
version = line.split('=')[1].strip().strip('\'')
break
if version is None:
raise RuntimeError('Could not determine version')

descr = """Reader and Writer for the European Data Format (EDF)"""

DISTNAME = PACKAGE_NAME
DESCRIPTION = descr
AUTHOR = 'Robert Oostenveld'
AUTHOR_EMAIL = 'r.oostenveld@donders.ru.nl'
MAINTAINER = 'Phillip Alday'
MAINTAINER_EMAIL = 'me@phillipalday.com'
URL = 'https://github.com/robertoostenveld/pyEDF'
LICENSE = 'BSD (3-clause)'
DOWNLOAD_URL = 'https://github.com/robertoostenveld/pyEDF'
VERSION = version

def package_tree(pkgroot):
"""Get the submodule list."""
# Adapted from MNE-Python
path = os.path.dirname(__file__)
subdirs = [os.path.relpath(i[0], path).replace(os.path.sep, '.')
for i in os.walk(os.path.join(path, pkgroot))
if '__init__.py' in i[2]]
return sorted(subdirs)

if __name__ == "__main__":
if os.path.exists('MANIFEST'):
os.remove('MANIFEST')

setup(name=DISTNAME,
author=AUTHOR,
author_email=AUTHOR_EMAIL,
maintainer=MAINTAINER,
maintainer_email=MAINTAINER_EMAIL,
include_package_data=True,
description=DESCRIPTION,
license=LICENSE,
url=URL,
version=VERSION,
download_url=DOWNLOAD_URL,
long_description=open('README.md').read(),
zip_safe=True, # the package can run out of an .egg file
classifiers=['Intended Audience :: Science/Research',
'Intended Audience :: Developers',
'License :: OSI Approved',
'Programming Language :: Python',
'Topic :: Software Development',
'Topic :: Scientific/Engineering',
'Operating System :: Microsoft :: Windows',
'Operating System :: POSIX',
'Operating System :: Unix',
'Operating System :: MacOS'],
platforms='any',
packages=package_tree(PACKAGE_NAME),
)