Repository: mne-tools/mne-python

Issue:
mne-python is either GPL or non-free now due to mne/io/edf/gdf_encodes.txt
mne/io/edf/gdf_encodes.txt from biosig says
```
# BioSig is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation; either
# Version 3 of the License, or (at your option) any later version.
#
# Alternative license: 
# This table of event codes can be used in any application 
# (without the restrictions of GPL) under the condition that this table 
# is not modified, changed, converted or transformed. No 
# derivative of any kind are allowed. Suggestions for improvement 
# and changes should be addressed to the author. 
```
so either then mne-python is effectively under GPL license or non-free (no modifications allowed)... what it is ? ;)  May be @schloegl could relax this restriction (I am really not sure why not to allow changes/fixes etc)?


Discussion:
AFAIK we didn't change the table, so we use the alternative license. Unlike the GPL, this alternative license only applies to this single file and does not automatically transfer to MNE.
On 08.08.19 22:01, Yaroslav Halchenko wrote:
> mne/io/edf/gdf_encodes.txt from biosig says
> ```
> # BioSig is free software; you can redistribute it and/or
> # modify it under the terms of the GNU General Public
> # License as published by the Free Software Foundation; either
> # Version 3 of the License, or (at your option) any later version.
> #
> # Alternative license: 
> # This table of event codes can be used in any application 
> # (without the restrictions of GPL) under the condition that this table 
> # is not modified, changed, converted or transformed. No 
> # derivative of any kind are allowed. Suggestions for improvement 
> # and changes should be addressed to the author. 
> ```
> so either then mne-python is effectively under GPL license or non-free (no modifications allowed)... what it is ? ;)  May be @schloegl could relax this restriction (I am really not sure why not to allow changes/fixes etc)?
>


I do allow changes - under the terms of GPLv3.

The code table is used to standardize codes for events, markers and
annotations. Compatibility can only be maintained if the table is
normative.  Therefore, this event table must stay public and nobody
should use a modified, non-public version of this table.  The BSD
license (used by MNE) is not sufficient to guarantee this.


Alois 





I understand but how do you allow then the existence of BSD / MIT licensed
readers for GDF files?

> Unlike the GPL, this alternative license only applies to this single file and does not automatically transfer to MNE

" is not modified, changed, converted or transformed" restrictions make it non-free (incompatible with BSD-3 license of MNE, must be stripped to get MNE to debian).  Moreover "converted" is IMHO a bad term, since under some stretch of interpretation then it is not usable at all since use of those would typically require internal (to the codebase) conversion to other data types/representations.  IMHO trying to enforce it this way provides only disadvantages/inconveniences without actually solving any problem (I really do not see people modifying this file for their own good). tables of values for formats are known to exist in other cases (e.g. iirc dcmtk and others) and I do not remember them having such restrictions.
I don't understand the reasoning either, but if we can't use this file then I suggest we remove it and return only the event codes instead of the text mappings from the file.
@schloegl are you asking us to remove the file with the consequence that mne cannot properly read GDF files?

Resolving patch:
diff --git a/mne/io/edf/_utils.py b/mne/io/edf/_utils.py
deleted file mode 100644
--- a/mne/io/edf/_utils.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# -*- coding: utf-8 -*-
-"""Helper functions for EDF, EDF+, BDF converters to FIF."""
-
-# Authors: Teon Brooks <teon.brooks@gmail.com>
-#          Martin Billinger <martin.billinger@tugraz.at>
-#          Nicolas Barascud <nicolas.barascud@ens.fr>
-#          Stefan Appelhoff <stefan.appelhoff@mailbox.org>
-#          Joan Massich <mailsik@gmail.com>
-#
-# License: BSD (3-clause)
-
-import os.path as op
-import re
-
-from ...utils import hashfunc
-
-
-def _load_gdf_events_lut():
-    fname = op.join(op.dirname(__file__), 'gdf_encodes.txt')
-    hash_ = hashfunc(fname, hash_type='md5')
-    # Linux or Windows line endings
-    if hash_ not in ('12134a9be7e0bfa5941e95f8bfd330f7',
-                     '41696b162526f559dd7d139352eae178'):
-        raise ValueError("File %s is corrupted. mdf5 hashes don't match." %
-                         fname)
-
-    # load the stuff
-    with open(fname, 'r') as fh:
-        elements = [line for line in fh if not line.startswith("#")]
-
-    event_id, event_name = list(), list()
-    for elem in elements:
-        event_id_i, *event_name_i = elem.split('\t')
-        event_id.append(int(event_id_i, 0))
-        clean_name = re.sub('[ \t]+', ' ', ' '.join(event_name_i))
-        clean_name = re.sub('\n', '', clean_name)
-        event_name.append(clean_name)
-
-    return dict(zip(event_id, event_name))
diff --git a/mne/io/edf/edf.py b/mne/io/edf/edf.py
--- a/mne/io/edf/edf.py
+++ b/mne/io/edf/edf.py
@@ -25,10 +25,6 @@
 from ...filter import resample
 from ...utils import copy_function_doc_to_method_doc, deprecated, fill_doc
 from ...annotations import Annotations, events_from_annotations
-from ._utils import _load_gdf_events_lut
-
-
-GDF_EVENTS_LUT = _load_gdf_events_lut()
 
 
 @deprecated('find_edf_events is deprecated in 0.18, and will be removed'
@@ -1437,6 +1433,6 @@ def _get_annotations_gdf(edf_info, sfreq):
     if events is not None and events[1].shape[0] > 0:
         onset = events[1] / sfreq
         duration = events[4] / sfreq
-        desc = [GDF_EVENTS_LUT.get(key, 'Undefined(%s)' % (key,))
-                for key in events[2]]
+        desc = events[2]
+
     return onset, duration, desc


Test patch:
diff --git a/mne/io/edf/tests/test_gdf.py b/mne/io/edf/tests/test_gdf.py
--- a/mne/io/edf/tests/test_gdf.py
+++ b/mne/io/edf/tests/test_gdf.py
@@ -16,7 +16,6 @@
 from mne.io.tests.test_raw import _test_raw_reader
 from mne.utils import run_tests_if_main
 from mne import pick_types, find_events, events_from_annotations
-from mne.io.edf.edf import GDF_EVENTS_LUT
 
 data_path = testing.data_path(download=False)
 gdf1_path = op.join(data_path, 'GDF', 'test_gdf_1.25')
@@ -33,7 +32,7 @@ def test_gdf_data():
     # Test Status is added as event
     EXPECTED_EVS_ONSETS = raw._raw_extras[0]['events'][1]
     EXPECTED_EVS_ID = {
-        'Undefined({})'.format(evs): i for i, evs in enumerate(
+        '{}'.format(evs): i for i, evs in enumerate(
             [32769, 32770, 33024, 33025, 33026, 33027, 33028, 33029, 33040,
              33041, 33042, 33043, 33044, 33045, 33285, 33286], 1)
     }
@@ -84,9 +83,4 @@ def test_gdf2_data():
                      eog=None, misc=None)
 
 
-def test_gdf_events_lut():
-    """Test something about GDF_EVENTS_LUT to make sure it has not changed."""
-    assert len(GDF_EVENTS_LUT) == 200
-
-
 run_tests_if_main()