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() ## ##