As we move towards using Python 3, I have encountered a problem related to 
the MetaArrays. Although not related to the graphics portion of pyqtgraph, 
MetaArrays are part of pyqtgraph. I suspect they are not widely used, but 
they are used extensively in acq4 (a separate project that depends on 
pyqtgraph).

MetaArrays written in Python 2 or Python 3 are readable in Python 2. 
However, neither seems to be readable in Python 3.  This seems to be 
related to the difference between strings and bytes in the two when 
interpreting part of the data. 

The specific error (test script of minimal working version is attached; see 
the code for usage)  is:

user: sandbox $ python test_ma.py read 2

Running under Python 3:  3.6.5
Reading metaarray_py2.ma
Traceback (most recent call last):
  File "test_ma.py", line 57, in <module>
    mdata = ma.MetaArray(file=fn)
  File 
"/Users/pbmanis/Desktop/Python/pyqtgraph/pyqtgraph/metaarray/MetaArray.py", 
line 135, in __init__
    self.readFile(file, **kwargs)
  File 
"/Users/pbmanis/Desktop/Python/pyqtgraph/pyqtgraph/metaarray/MetaArray.py", 
line 752, in readFile
    meta = MetaArray._readMeta(fd)
  File 
"/Users/pbmanis/Desktop/Python/pyqtgraph/pyqtgraph/metaarray/MetaArray.py", 
line 777, in _readMeta
    meta += line
*TypeError: must be str, not bytes*
user: sandbox $ python test_ma.py read 3
Running under Python 3:  3.6.5
Reading metaarray_py3.ma
Traceback (most recent call last):
  File "test_ma.py", line 57, in <module>
    mdata = ma.MetaArray(file=fn)
  File 
"/Users/pbmanis/Desktop/Python/pyqtgraph/pyqtgraph/metaarray/MetaArray.py", 
line 135, in __init__
    self.readFile(file, **kwargs)
  File 
"/Users/pbmanis/Desktop/Python/pyqtgraph/pyqtgraph/metaarray/MetaArray.py", 
line 752, in readFile
    meta = MetaArray._readMeta(fd)
  File 
"/Users/pbmanis/Desktop/Python/pyqtgraph/pyqtgraph/metaarray/MetaArray.py", 
line 777, in _readMeta
    meta += line
*TypeError: must be str, not bytes*

Whereas in Python 2 we can read or write python 2 or 3 files just fine.
user: sandbox $ python test_ma.py read 3
Running under Python 2:  2.7.14
user metaarray_py3.ma (displays data)


The problem lies in this routine around line 777 in MetaArray.py:
    @staticmethod
    def _readMeta(fd):
        """Read meta array from the top of a file. Read lines until a blank 
line is reached.
        This function should ideally work for ALL versions of MetaArray.
        """
        meta = ''
        ## Read meta information until the first blank line
        while True:
            line = fd.readline().strip()
            if line == '':
                break
            meta += line
        ret = eval(meta)
        #print ret
        return ret

I have tried to clean this up to be agnostic with respect to python 
versions, but without success. I suspect there is a simple way to do this, 
but I haven't found it yet.

Any ideas?

--Paul



-- 
You received this message because you are subscribed to the Google Groups 
"pyqtgraph" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/pyqtgraph/a763c66e-dd2d-4715-a605-d5417c921b6c%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
from __future__ import print_function
"""
Test metaarrays for python 2.7 versus 3.5+

Usage:
First, generate the .ma file from the version of Python you are running, and switch versions/enviornments and generate the other test file
>python test_ma.py write 2  (note the write code will generate the file appropriate for the version you are running under).
Then, try to read:
python test_ma.py read 2 (or read 3)


"""

import sys
import platform
import numpy as np
import pyqtgraph.metaarray as ma
import matplotlib.pyplot as mpl

if len(sys.argv) == 3:
    mode = sys.argv[1]
    version = sys.argv[2]

else:
    print('Call: python test_ma.py [read | write] [2|3]')
    print('must specify read or write (which also does read) for the .ma file')
    print( sys.argv)
    exit(1)

if mode not in ['read', 'write']:
    raise ValueError('Mode must be read or write')
if version not in ['2', '3']:
    raise ValueError ('version must be 2 or 3')


if sys.version_info[0] == 2:
    print('Running under Python 2: ', platform.python_version())
elif sys.version_info[0] == 3:
    print('Running under Python 3: ', platform.python_version())


if mode == 'write':
    print('Writing .ma file')# create a metaarray file on disk (problem is reading py2 files in py 3)
    datav = np.random.random((1024, 1))
    datai = np.random.random((1024, 1))
    time = np.arange(0, 102.4, 0.1)

    mdata = ma.MetaArray(np.array([datav, datai]),
            info=[
            {"name": "Signal", "cols": [
                {"name": "Voltage", "units": "V"},
                {"name": "Current", "units": "V"},
                ]
             },
            {"name": "Time", "units": "msec", "values": time},
            {"name": "Trial"},
            {"note": "Just some extra info"}
    ])
    mdata.write('metaarray_py%d.ma'%sys.version_info[0])  # only write for the python version we are in
    
# regardless, read the file for the version we specified
fn = 'metaarray_py%s.ma' % version
print('Reading %s' % fn)
mdata = []
mdata = ma.MetaArray(file=fn)
f, ax = mpl.subplots(2, 1)
ax = ax.ravel()

ax[0].plot(mdata.xvals('Time'), mdata['Signal': 'Voltage'].view(np.ndarray), 'k')
ax[1].plot(mdata.xvals('Time'), mdata['Signal': 'Current'].view(np.ndarray), 'cyan')
mpl.show()

Reply via email to