Laydi project directory for testing the new project structure.
This commit is contained in:
parent
ebda69049e
commit
f29d48e879
|
@ -0,0 +1,281 @@
|
|||
import os, os.path
|
||||
import sys
|
||||
import configobj
|
||||
|
||||
from laydi import dataset
|
||||
|
||||
NAME = "laydi-cmd"
|
||||
VERSION = "0.1.0"
|
||||
PROJECT_VERSION_STRING = "Laydi project version 1"
|
||||
|
||||
def is_project_directory(dirname):
|
||||
"""Verifies that a directory is a laydi project"""
|
||||
|
||||
if not os.path.isdir(dirname):
|
||||
return False
|
||||
|
||||
## Verify that the version is correct.
|
||||
version_fn = os.path.join(dirname, "VERSION")
|
||||
if not os.path.exists(version_fn):
|
||||
return False
|
||||
fd = open(version_fn)
|
||||
line = fd.readline()
|
||||
fd.close()
|
||||
|
||||
if fd.strip() != PROJECT_VERSION_STRING:
|
||||
return False
|
||||
|
||||
## Require directories to be present.
|
||||
if not os.path.isdir(os.path.join(dirname, "annotations")):
|
||||
return False
|
||||
if not os.path.isdir(os.path.join(dirname, "data")):
|
||||
return False
|
||||
if not os.path.isdir(os.path.join(dirname, "selections")):
|
||||
return False
|
||||
if not os.path.isdir(os.path.join(dirname, "exports")):
|
||||
return False
|
||||
|
||||
## If no tests failed, return True
|
||||
return True
|
||||
|
||||
|
||||
def make_project_directory(dirname, force=False):
|
||||
"""Creates a project directory
|
||||
|
||||
force: ignore that directory exists and proceed anyway.
|
||||
"""
|
||||
if os.path.exists(dirname) and not force:
|
||||
return False
|
||||
|
||||
rootdir = dirname
|
||||
anndir = os.path.join(dirname, "annotations")
|
||||
seldir = os.path.join(dirname, "selections")
|
||||
datadir = os.path.join(dirname, "data")
|
||||
exportdir = os.path.join(dirname, "exports")
|
||||
version_file_path = os.path.join(dirname, "VERSION")
|
||||
|
||||
os.makedirs(rootdir)
|
||||
for d in [anndir, seldir, datadir, exportdir]:
|
||||
os.mkdir(d)
|
||||
|
||||
fd = open(version_file_path, "w")
|
||||
print >> fd, PROJECT_VERSION_STRING
|
||||
fd.close()
|
||||
|
||||
|
||||
|
||||
class Universe(object):
|
||||
"""A Universe is a collection of all existing identifiers in a set of datasets"""
|
||||
|
||||
def __init__(self):
|
||||
self.refcount = {}
|
||||
|
||||
def register_dim(self, dim):
|
||||
"""Increase reference count for identifiers in Dimension object dim"""
|
||||
d = self.refcount.get(dim.name, None)
|
||||
if d == None:
|
||||
d = {}
|
||||
self.refcount[dim.name] = d
|
||||
for i in dim:
|
||||
d[i] = d.get(i, 0) + 1
|
||||
|
||||
def register_ds(self, ds):
|
||||
"""Increase reference count for identifiers in all Dimensions of dataset ds"""
|
||||
for dim in ds.dims:
|
||||
self.register_dim(dim)
|
||||
|
||||
def unregister_dim(self, dim):
|
||||
"""Update reference count for identifiers in Dimension object dim
|
||||
Update reference count for identifiers in Dimension object dim, and remove all
|
||||
identifiers with a reference count of 0, as they do not (by definition) exist
|
||||
any longer.
|
||||
"""
|
||||
ids = self.refcount[dim.name]
|
||||
for i in dim:
|
||||
refcount = ids[i]
|
||||
if refcount == 1:
|
||||
ids.pop(i)
|
||||
else:
|
||||
ids[i] -= 1
|
||||
if len(ids) == 0:
|
||||
self.refcount.pop(dim.name)
|
||||
|
||||
|
||||
def unregister_ds(self, ds):
|
||||
"""Update reference count for identifiers along Dimensions in Dataset ds.
|
||||
Update reference count for identifiers along all Dimensions in
|
||||
Dataset ds, and remove all identifiers with a reference count of 0,
|
||||
as they do not (by definition) exist any longer.
|
||||
"""
|
||||
for dim in ds:
|
||||
self.register_dim(dim)
|
||||
|
||||
def register(self, obj):
|
||||
if isinstance(obj, Dataset):
|
||||
self.register_ds(obj)
|
||||
else:
|
||||
self.register_dim(obj)
|
||||
|
||||
def unregister(self, obj):
|
||||
if isinstance(obj, Dataset):
|
||||
self.unregister_ds(obj)
|
||||
else:
|
||||
self.unregister_dim(obj)
|
||||
|
||||
def __getent___(self, dimname):
|
||||
return set(self.references[dimname].keys())
|
||||
|
||||
def __iter__(self):
|
||||
return self.references.keys().__iter__()
|
||||
|
||||
|
||||
class Dimension(object):
|
||||
"""A Dimension represents the set of identifiers an object has along an axis.
|
||||
"""
|
||||
def __init__(self, name, ids=[]):
|
||||
self.name = name
|
||||
self.idset = set(ids)
|
||||
self.idlist = list(ids)
|
||||
|
||||
if len(self.idset) != len(self.idlist):
|
||||
raise Exception("Duplicate identifiers are not allowed")
|
||||
|
||||
def __getitem__(self, element):
|
||||
return self.idlist[element]
|
||||
|
||||
def __getslice__(self, start, end):
|
||||
return self.idlist[start:end]
|
||||
|
||||
def __contains__(self, element):
|
||||
return self.idset.__contains__(element)
|
||||
|
||||
def __str__(self):
|
||||
return "%s: %s" % (self.name, str(self.idlist))
|
||||
|
||||
def __len__(self):
|
||||
return len(self.idlist)
|
||||
|
||||
def __iter__(self):
|
||||
return iter(self.idlist)
|
||||
|
||||
def intersection(self, dim):
|
||||
return self.idset.intersection(dim.idset)
|
||||
|
||||
def as_tuple(self):
|
||||
return (self.name, self.idlist)
|
||||
|
||||
|
||||
class DirectoryNotifier(object):
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
self.files = {}
|
||||
self.subdirs = {}
|
||||
self.timestamp = -1
|
||||
self.file_listeners = {}
|
||||
self.dir_listeners = {}
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
now = time.time()
|
||||
for fn in os.listdir(self.path):
|
||||
if os.getctime(fn) > self.timestamp:
|
||||
ext = os.path.splitext(fn)[1]
|
||||
|
||||
|
||||
def listen_files(self, obj, ext=None):
|
||||
listeners = self.file_listeners
|
||||
if listeners.has_key(ext):
|
||||
listeners[ext].append(obj)
|
||||
else:
|
||||
listeners[ext] = [obj]
|
||||
|
||||
|
||||
def listen_dirs(self, obj, ext=None):
|
||||
listeners = self.dir_listeners
|
||||
if listeners.has_key(ext):
|
||||
listeners[ext].append(obj)
|
||||
else:
|
||||
listeners[ext] = [obj]
|
||||
|
||||
|
||||
class DataDirectory(object):
|
||||
def __init__(self, dirname, recursive=False, universe=None):
|
||||
self.dirname = dirname
|
||||
|
||||
## Read datasets, plots and optionally subdirectories
|
||||
datasets = []
|
||||
ds_fn = {}
|
||||
plots = []
|
||||
plot_fn = {}
|
||||
subdirs = []
|
||||
subdir_fn = {}
|
||||
update_time = 0
|
||||
|
||||
self.update()
|
||||
|
||||
def update(self):
|
||||
## Remember new timestamp.
|
||||
now = time.time()
|
||||
|
||||
## Read configuration
|
||||
ini_fn = os.path.join(dirname, "directory.ini")
|
||||
if os.path.isfile(ini_fn) and os.getctime(ini_fn) > self.update_time:
|
||||
self.config = configobj(ini_fn, unrepr=True)
|
||||
|
||||
for fn in os.listdir(self.dirname):
|
||||
ext = os.path.splitext(fn)[1]
|
||||
if ext == "ftsv":
|
||||
ds = dataset.read_ftsv(fn)
|
||||
if universe is not None:
|
||||
universe.register_ds(ds)
|
||||
elif ext == "plot":
|
||||
plot = configobj(fn, unrepr=True)
|
||||
plots.append(plot)
|
||||
elif os.path.isdir(fn) and recursive:
|
||||
subdirs.append(DataDirectory(fn, recursive=True, universe=universe))
|
||||
|
||||
## Set new update time
|
||||
self.update_time = now
|
||||
|
||||
|
||||
def SelectionDirectory(object):
|
||||
def __init__(self, dirname):
|
||||
pass
|
||||
|
||||
class Project(object):
|
||||
def __init__(self, dirname):
|
||||
"""Opens a project directory. The directory must exist and be a valid project."""
|
||||
|
||||
## Set path names.
|
||||
self.rootdir = dirname
|
||||
self.anndir = os.path.join(dirname, "annotations")
|
||||
self.seldir = os.path.join(dirname, "selections")
|
||||
self.datadir = os.path.join(dirname, "data")
|
||||
self.exportdir = os.path.join(dirname, "exports")
|
||||
version_file_path = os.path.join(dirname, "VERSION")
|
||||
|
||||
self.universe = Universe()
|
||||
|
||||
self.data = DataDirectory(self.datadir, universe=self.universe, recursive=True)
|
||||
|
||||
def update(self):
|
||||
for datadir in self.data:
|
||||
datadir.update()
|
||||
|
||||
## class Dataset
|
||||
##
|
||||
##
|
||||
## class Plot
|
||||
##
|
||||
##
|
||||
## class Selection
|
||||
##
|
||||
##
|
||||
## class Annotation
|
||||
##
|
||||
##
|
||||
## class DataDirectory()
|
||||
##
|
||||
##
|
||||
|
||||
|
Reference in New Issue