Skip to content
Snippets Groups Projects
Commit f0a21f85 authored by François  LAURENT's avatar François LAURENT
Browse files

working: load, check

parent 7dce7465
No related branches found
No related tags found
No related merge requests found
......@@ -3,14 +3,17 @@ from larva.qc import qc_check
@qc_check(input_type='datasource')
def spine_outline_sync(ctrl, datasource):
from ..spine_outline import SpineOutline
from larva.io.chore.spine_outline import (
find_associated_file, load_spine, load_outline,
)
file1 = datasource
file2 = SpineOutline(file1).find_associated_file()
file2 = find_associated_file(file1)
if file2 is None:
ctrl.report(desc='no associated file found')
else:
df1 = SpineOutline.load(file1)
df2 = SpineOutline.load(file2)
# load_outline should work with spine files
df1 = load_outline(file1)
df2 = load_outline(file2)
nrows1 = df1.shape[0]
nrows2 = df2.shape[0]
if nrows1 != nrows2:
......
......@@ -102,7 +102,7 @@ def rtrim_nan(filt):
trimmed = filt[:stop]
return trimmed
def write_outline(filepath, df, append=False, float_format='.3f'):
def save_outline(filepath, df, append=False, float_format='.3f'):
if float_format.startswith('%'):
float_format = float_format[1:]
date_time, larva_id = df['date_time'], df['larva_id']
......@@ -116,10 +116,11 @@ def write_outline(filepath, df, append=False, float_format='.3f'):
f.write(fmt.format(newline, date_time, larva_id, *points))
newline = '\n'
from .check import \
from .check import (
spine_outline_default_qc_checks,
spine_specific_default_qc_checks,
outline_specific_default_qc_checks,
)
from larva.qc.file import QCFileBackend
......@@ -135,5 +136,5 @@ outline_backend = QCFileBackend(
spine_outline_default_qc_checks + outline_specific_default_qc_checks,
)
__all__ = ['load_outline', 'write_outline', 'read_larvae',
__all__ = ['load_outline', 'save_outline', 'read_larvae',
'spine_backend', 'outline_backend']
import os
from larva.qc.file import QCFile
from larva.qc.file import QCFile, load, check, save
from .backend.dataframe import purepy as default
......@@ -41,14 +41,14 @@ class Outline(SpineOutline):
SpineOutline.__init__(self, filepath)
self.backend = default.outline_backend
load_spine = Spine.load
load_outline = Outline.load
load_spine = load(Spine)
load_outline = load(Outline)
check_spine = Spine.check
check_outline = Outline.check
check_spine = check(Spine)
check_outline = check(Outline)
save_spine = Spine.save
save_outline = Outline.save
save_spine = save(Spine)
save_outline = save(Outline)
__all__ = [
'Spine',
......
import hdf5storage
def load_trx(filepath, varnames=[]):
if varnames:
if isinstance(varnames, str):
varnames = varnames.split()
trx = hdf5storage.loadmat(filepath,
variable_names=[ 'trx/'+varname for varname in varnames ])
else:
trx = hdf5storage.loadmat(filepath)
trx = { varname[4:]: trx[varname] for varname in trx }
return trx
from larva.qc.file import QCFileBackend
trx_backend = QCFileBackend(
load_trx,
NotImplemented,
[],
)
__all__ = ['load_trx', 'trx_backend']
from larva.qc.file import QCFile
import numpy as np
from larva.qc.file import QCFile, asfun, load, check, save
import h5py
import hdf5storage
from .backend import hdf5storage as default
class Trx(QCFile):
__slots__ = ()
def __init__(self, filepath=None):
QCFile.__init__(self, filepath)
self.backend = default.trx_backend
def _list_varnames(self):
def list_varnames(self):
filepath = self.filepath
if not filepath:
raise ValueError('filepath is not defined')
try:
store = h5py.File(filepath, 'r')
except OSError:
......@@ -19,22 +24,10 @@ class Trx(QCFile):
finally:
store.close()
@classmethod
def list_varnames(cls, filepath=None):
if isinstance(cls, type):
if filepath is None:
raise ValueError('filepath is not defined')
else:
return Trx(filepath)._list_varnames()
else:
self = cls
return self._list_varnames()
list_trx_varnames = Trx.list_varnames
load_trx = Trx.load
check_trx = Trx.check
save_trx = Trx.save # not implemented
list_trx_varnames = asfun(Trx, Trx.list_varnames)
load_trx = load(Trx)
check_trx = check(Trx)
save_trx = save(Trx) # not implemented
__all__ = [
'Trx',
......
......@@ -3,12 +3,12 @@ from .check import QCChecks
class QCFileBackend:
__slots__ = '_load', '_write', '_default_qc_checks'
__slots__ = '_load', '_save', '_default_qc_checks'
def __init__(self, load, write, default_qc_checks):
def __init__(self, load, save, default_qc_checks):
if not callable(load):
raise TypeError('load is not callable')
if not callable(save):
if not (callable(save) or save is NotImplemented):
raise TypeError('save is not callable')
self._load = load
self._save = save
......@@ -76,11 +76,8 @@ class QCFile:
raise AttributeError('not a list')
@classmethod
def reify(cls, *args, filepath=None, copy=False, **kwargs):
def reify(cls, *args, filepath=None, **kwargs):
"""
Switch from class method to regular method, suitable for
`load` and especially `check`.
The first positional argument, if of type *str* or *Path*,
is interpreted as *filepath*, and a *TypeError* exception
is raised if keyworded *filepath* is also defined.
......@@ -90,40 +87,18 @@ class QCFile:
filepath = args[0]
else:
raise TypeError('filepath is specified twice')
if isinstance(cls, type):
self = cls(filepath=filepath)
elif copy:
self = cls
cls = type(self)
if filepath is None:
filepath = self.filepath
new = cls(filepath=filepath)
new.backend = self.backend
self = new
else:
self = cls
if filepath:
if self.filepath:
if filepath != self.filepath:
raise ValueError('filepath is already defined')
else:
self.filepath = filepath
self = cls(filepath=filepath)
if not self.filepath:
raise ValueError('filepath is not defined')
return self
@classmethod
def load(cls, filepath=None, **kwargs):
self = cls.reify(filepath=filepath)
return self.backend.load(**kwargs)
def load(self, *args, **kwargs):
return self.backend.load(self.filepath, *args, **kwargs)
@classmethod
def check(cls, data=None, policy=None, **kwargs):
kwargs['copy'] = False
self = cls.reify(data, **kwargs)
def check(self, data=None, policy=None, **kwargs):
# make data lazily available
if data is None or isinstance(data, (str, Path)):
data = self.load
if data is None:
data = self.load(**kwargs)
# run the checks, fix the data and collect the diagnoses
diagnoses = dict()
for check in self.qc:
......@@ -134,59 +109,39 @@ class QCFile:
#
return data, diagnoses
@classmethod
def save(cls, *args, **kwargs):
may_be_path = lambda a: isinstance(a, (str, Path))
may_be_data = lambda a: not may_be_path(a)
# parse the arguments.
# first positional argument can be:
# - filepath, or
# - data if filepath is defined as a keyword argument;
# second positional argument can only be data;
# a variable cannot be defined twice, be it
# a positional or keyword argument;
args = list(args)
if args and may_be_path(args[0]):
filepath = args.pop(0)
if 'filepath' in kwargs:
raise ValueError('filepath is defined twice')
else:
filepath = kwargs.pop('filepath', None)
if args and may_be_data(args[0]):
data = args.pop(0)
if 'data' in kwargs:
raise ValueError('data is defined twice')
else:
data = kwargs.pop('data', None)
if args:
raise ValueError(f'cannot interprete arguments: {args}')
# extract missing information from the parent object
# if save is called as a regular method
if isinstance(cls, type):
if data is None:
raise ValueError('data is not defined')
if not filepath:
raise ValueError('filepath is not defined')
output_file = cls.reify(filepath=filepath)
else:
self = cls
if filepath is None:
if data is None:
raise ValueError('neither filepath nor data are defined')
output_file = self.reify(filepath=filepath, copy=True)
else:
if data is None:
input_file = self
data = input_file.load()
else:
output_file = self
# save
output_file.backend.save(data, *args, **kwargs)
def save(self, data, *args, **kwargs):
self.backend.save(self.filepath, data, *args, **kwargs)
def __getattr__(self, attr):
return self.qc.__getattr__(attr)
def asfun(cls, met):
def _fun(filepath, *args, **kwargs):
self = cls(filepath)
return met(self, *args, **kwargs)
_fun.__doc__ = met.__doc__
return _fun
load = lambda cls: asfun(cls, cls.load)
save = lambda cls: asfun(cls, cls.save)
def check(cls):
def _check(filepath_or_data, policy=None, **kwargs):
if isinstance(filepath_or_data, (str, Path)):
filepath = filepath_or_data
self = cls(filepath)
data = None
else:
self = cls()
data = filepath_or_data
return self.check(data, policy, **kwargs)
_check.__doc__ = cls.check.__doc__
return _check
__all__ = [
'QCFileBackend',
'QCFile',
'load',
'check',
'save',
]
......@@ -6,7 +6,7 @@ from setuptools import setup
from codecs import open
import os.path
install_requires = ['h5py', 'scipy', 'numba']
install_requires = ['h5py', 'hdf5storage']
extras_require = {}
setup_requires = ['pytest-runner']
tests_require = ['pytest']
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment