# -*- coding: utf-8 -*- from sqlalchemy import create_engine, MetaData, asc, desc from sqlalchemy.ext.automap import automap_base from sqlalchemy.orm import Session, scoped_session, sessionmaker class Project(): """ A helper class representing a Citavi project. """ def __init__(self, sqlite_file): """ Constructor to get absolute path to sqlite. """ self.sqlite_file = sqlite_file self._is_open = False self._is_error = False self._sa = {} # Object namespace for sqlalchemy related objects def __del__(self): """ Destructor to close the citavi file. """ self.close() def is_valid(self): """ This method returns False in case the given sqlite file is not a valid Citavi project. """ return self._is_open and not self._is_error def get_persons(self): """ Returns all persons from the Citavi project. """ try: person_class = self._sa_sqlite_autobase.classes.Person citavi_persons = self._sa_sqlite_session.query(person_class).order_by(asc('ID')).all() return citavi_persons except Exception, e: print e self._is_error = True # TODO: better error handling! print str(u"An error occured within a get_persons call!") return False def get_person_by_uuid(self, uuid): """ Returns a person from the Citavi project by their uuid. """ try: person_class = self._sa_sqlite_autobase.classes.Person citavi_person = self._sa_sqlite_session.query(person_class).filter(u'ID=\'' + unicode(uuid) + u'\'').all() return citavi_person[0] except Exception, e: print e self._is_error = True # TODO: better error handling! print str(u"An error occured within a get_person_by_uuid call!") return False def open(self): """ Public method to open a citavi project file. """ if not self._is_open: self._open() def close(self): """ Public method to close a citavi project file. """ if self._is_open: self._close() def _open(self): """ Internal method to open a citavi project file. """ try: self._sa_sqlite_engine = create_engine(u'sqlite+pysqlite:///' + self.sqlite_file) self._sa_sqlite_session = scoped_session(sessionmaker(bind=self._sa_sqlite_engine)) # Caution: SQLAlchemy Sessions are per thread! self._sa_sqlite_meta = MetaData(bind=self._sa_sqlite_engine) self._sa_sqlite_meta.reflect() self._sa_sqlite_autobase = automap_base() self._sa_sqlite_autobase.prepare(self._sa_sqlite_engine, reflect=True) self._is_open = True except: self._is_error = True self._is_open = False def _close(self): """ Internal method to actually close a citavi project file. """ try: del self._sa.sqlite_engine del self._sa.sqlite_session del self._sa.sqlite_meta del self._sa.sqlite_autobase del self._sa.sqlite_engine self._is_open = False except: self._is_error = True self._is_open = True class ProjectManager(): """ A backend to provide fast access to Citavi identity data. """ def __init__(self): """ Constructor initializing dictionary for instances of Project. """ self._projects = {} def __del__(self): """ Destructor making sure all Project instances are properly deconstructed. """ self._projects.clear() def get_path_for_project_id(self, project_id): return u'media/citavi/project_' + unicode(project_id) + u'.ctt4' def _add_project(self, project_id): """ Internal method to add a Project instance if not existing. """ if project_id not in self._projects: self._projects[project_id] = Project(self.get_path_for_project_id(project_id)) self._projects[project_id].open() def get_person_by_uuid(self, project_id, uuid): """ Returns the person matching the given uuid. """ self._add_project(project_id) return self._projects[project_id].get_person_by_uuid(uuid) def get_persons_from_project(self, project_id): """ Returns all person from a projects. """ self._add_project(project_id) return self._projects[project_id].get_persons()