def test_remove(): env = ODir('bin', push_up=True) a1 = env.add('A1') env.A1.add('A2') b1 = env.add('B1') env.B1.add('B2') assert hasattr(env, 'A1') assert hasattr(env, 'B1') assert hasattr(env.A1, 'A2') assert hasattr(env.B1, 'B2') assert hasattr(env, 'A2') assert hasattr(env, 'B2') env.A1.remove_parent() g = env.descendents() # Cannot access A1 from env. Can still access A2 from a1 assert not hasattr(env, 'A1') assert not hasattr(env, 'A2') assert hasattr(a1, 'A2') # B1 and B2 are still exist assert hasattr(env, 'B1') assert hasattr(env.B1, 'B2') assert hasattr(env, 'B2')
def test_attr(): env = ODir('bin') name = 'somethigldj' attr = 'asldkfjlsdfj' env.add(name, attr=attr) assert hasattr(env, attr) assert not hasattr(env, name)
def __init__(self, dir, name="FishTank", meta_dir=None, meta_name=None): """ SessionManager constructor :param dir: directory :type dir: str :param name: name of the folder :type name: str :param meta_dir: directory to store the metadata :type meta_dir: str :param meta_name: name of the file to store the metadata :type meta_name: str """ super().__init__(name, push_up=False, check_attr=False) self.set_dir(dir) # Add metadata (has default) # this is where session manager information will be stored if meta_dir is None: meta_dir = self.DEFAULT_METADATA_LOC if meta_name is None: meta_name = self.DEFAULT_METADATA_NAME self.metadata = ODir(meta_dir) self.metadata.add_file(meta_name, 'env_settings') self._curr_session_name = None
def test_paths(): env = ODir('bin') env.add('session1') env.session1.add('cat1') env.session1.add('cat2') assert len(env.paths) == 4 print(env.paths)
def test_list_dirs(): env = ODir('bin') env.add('A1').add('B1') env.add('C1').add("D1") dirs = env.list_dirs() assert env.A1 in dirs assert env.C1 in dirs assert not env.B1 in dirs assert not env.D1 in dirs
def test_dont_sanitize_attr(): env = ODir('bin') with pytest.raises(AttributeError): env.add('in') env.add('in', attr='myin') assert env.has('myin') assert not env.has('in')
def env(tmpdir): tmpdir = str(tmpdir) env = ODir('bin') env.set_dir(tmpdir) env.add('A1') env.A1.add('A2') env.add('B1') env.B1.add('B2') return env
def test_print_tree(): env = ODir('bin', push_up=True) env.add('session1') env.session1.add('cat1') env.session1.add('cat2') env.add('session2') env.session2.add('cat1', attr="s2cat1") print(env._children) env.print()
def a(request): env = ODir('bin', push_up=request.param) labels = ['a', 'b'] for l1 in labels: env.add(l1) assert hasattr(env, l1) level = getattr(env, l1) for l2 in labels: next_level = l1 + l2 getattr(env, l1).add(next_level) if request.param: assert hasattr(env, next_level) else: assert not hasattr(env, next_level) assert hasattr(level, next_level)
def test_remove_children(): env = ODir('bin', push_up=True) a1 = env.add('A1') env.A1.add('A2') b1 = env.add('B1') env.B1.add('B2') assert hasattr(env, 'A1') assert hasattr(env, 'B1') assert hasattr(env.A1, 'A2') assert hasattr(env.B1, 'B2') assert hasattr(env, 'A2') assert hasattr(env, 'B2') print(env.children.remove_parent()) g = env.descendents() assert len(g) == 0
def test_path(): env = ODir('bin') env.add('session1') env.session1.add('cat1') env.session1.add('cat2') env.add('session2') env.session2.add('cat1', attr="s2cat1") assert str(env.path) == 'bin' assert str(env.s2cat1.path) == 'bin/session2/cat1' assert str(env.cat1.path) == 'bin/session1/cat1' assert str(env.cat2.path) == 'bin/session1/cat2'
def test_list_files(): env = ODir('bin') env.add('A1').add_file('afile') env.add('C1').add_file("dfile") env.add_file('efile') env.add_file('ffile') files = env.list_files() assert not env.A1 in files assert not env.afile in files assert not env.C1 in files assert not env.dfile in files assert env.efile in files assert env.ffile in files
def test_unsanitized_attr(): env = ODir('bin') assert env.add('something') == env.add('something') assert env.something.add('core') == env.add('something').add( 'core') == env.something.core with pytest.raises(AttributeError): env.add('alskdf;;asd;flj') with pytest.raises(AttributeError): env.add('in') with pytest.raises(AttributeError): env.add('something', attr='somethingelse')
class SessionManager(ODir): """ Manages multiple :class:`SessionEnvironment` instances. SessionEnvironments live in a single directory managed by this class. Information about where the SessionManager directory resides is stored in the 'environment_data/environment_settings.json` file. By default, this is located where ParrotFish is installed so that is can be used globally on the machine. Alternatively, a SessionManager can be constructed that uses a new environement_settings file. The **environment_settings.json** also stores an encryption key so that :class:`SessionEnvironment`s can be decrypted and used properly. Example session structure:: meta_dir └──environment_data └──environment_settings.json (information about top directory) SessionManagerName (Master or root directory) |──SessionEnvironment1 (Aquarium session) | └──Category1 (Protocol Category) | |──.env_pkl (SessionEnvironment1's AqSession) | |──protocols (protocols folder) | | |──OperationType1 | | | |──OperationType1.json | | | |──OperationType1.rb | | | |──OperationType1__cost_model.rb | | | |──OperationType1__documentation.rb | | | |──OperationType1__precondition.rb | | | └──test_data.rb | | └──LibraryType1 | | |──LibraryType1.rb | | └──LibraryType1.json | └──OperationType1 └──SessionEnvironment2 └── ... """ DEFAULT_METADATA_LOC = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'environment_data') DEFAULT_METADATA_NAME = 'environment_settings.json' def __init__(self, dir, name="FishTank", meta_dir=None, meta_name=None): """ SessionManager constructor :param dir: directory :type dir: str :param name: name of the folder :type name: str :param meta_dir: directory to store the metadata :type meta_dir: str :param meta_name: name of the file to store the metadata :type meta_name: str """ super().__init__(name, push_up=False, check_attr=False) self.set_dir(dir) # Add metadata (has default) # this is where session manager information will be stored if meta_dir is None: meta_dir = self.DEFAULT_METADATA_LOC if meta_name is None: meta_name = self.DEFAULT_METADATA_NAME self.metadata = ODir(meta_dir) self.metadata.add_file(meta_name, 'env_settings') self._curr_session_name = None def register_session(self, login, password, aquarium_url, name): """ Registers a new session by creating a AqSession, creating a SessionEnvironment and adding it to the SessionManager """ if name in self.sessions: logger.warning("'{}' already exists!".format(name)) return key = str.encode(self.__meta['encryption_key']) session_env = SessionEnvironment( name, login, password, aquarium_url, key) self._add_session_env(session_env) def remove_session(self, name): """ Removes and deletes a managed session :param name: name of the session to delete :type name: str :return: None :rtype: None """ session = self.get(name) session.remove_parent() session.rmdirs() def _add_session_env(self, session_env): """Adds the session environment to the session manager""" self._add(session_env.name, session_env, push_up=False, check_attr=False) @property def __meta(self): if not self.metadata.env_settings.exists(): self.save() return self.metadata.env_settings.load_json() @property def current_env(self): """Current session environment""" if self._curr_session_name is None: return None return self.get(self._curr_session_name) @property def current_session(self): """Returns the current session""" if self._curr_session_name is None: return None return self.get_session(self._curr_session_name) def set_current(self, name): """Sets the current session name""" if name is None: return if name in self.sessions: self._curr_session_name = name else: logger.warning("'{}' not in sessions ({})".format( name, ', '.join(self.sessions.keys()))) @property def session_env_list(self): """Return all session environments""" return [env for env in self.list_dirs() if isinstance(env, SessionEnvironment)] @property def sessions(self): """Returns all sessions""" return {env.name: env.aquarium_session for env in self.session_env_list} def get_session(self, name): """Gets a AqSession by name""" session_env = self.get(name) return session_env.aquarium_session def delete_session(self, name): """Deletes a session, removing the folders and files as well as the abstract ODir link""" session_env = self.get(name) session_env.rmdirs() session_env.remove_parent() def move_repo(self, path): """Move all of the folders to a new location""" super().mvdirs(path) self.save() def __new_encryption_key(self): return Fernet.generate_key() def save(self, force_new_key=False, key=None): """Save the metadata""" encryption_key = None if not self.metadata.env_settings.exists() or force_new_key: if key is None: logger.warning( "No encryption key found. Generating new key...") encryption_key = self.__new_encryption_key().decode() else: encryption_key = key else: encryption_key = self.metadata.env_settings.load_json()[ 'encryption_key'] self.metadata.env_settings.dump_json( { "root": str(self.abspath), 'current': self._curr_session_name, "updated_at": str(datetime.datetime.now()), "version": __version__, "encryption_key": encryption_key, "container_id": self.get_container_id() }, indent=4) self.save_environments() def load(self, meta=None): """Load from the metadata""" if meta is None: meta = self.__meta if __version__ != meta['version']: logger.warning("Version mismatched! Environment data stored using " "ParrotFish version '{}' but currently using '{}'" .format(meta['version'], __version__)) # load encryption key from meta encryption_key = meta['encryption_key'] env = self.load_environments(encryption_key) env.set_current(meta['current']) self.save() return env def save_environments(self): """Save all of the session environments""" for session_env in self.session_env_list: session_env.save_to_pkl() def update_encryption_key(self, new_key): """ Updates the encryption key used to decrypt :class:`SessionEnvironment`s """ old_key = self.__meta['encryption_key'] for session_env in self.session_env_list: if session_env: session_env.update_encryption_key(old_key, new_key) # TODO: consolidate password hashes here def load_environments(self, encryption_key): """ Collects the SessionEnvironment pickles and returns a SessionManager with these session_environments. For examples `dir="User/Documents/Fishtank"` would load a SessionManager with the name "Fishtank." Environments would be loaded from `User/Documents/FishTank/*/.env_pkl` """ meta = self.__meta self.name = os.path.basename(self.metadata.env_settings.name) # set root path root_dir = os.path.dirname(meta['root']) root_name = os.path.basename(meta['root']) self.set_dir(root_dir) self.name = root_name env_pkls = glob(os.path.join(str(self.abspath), "*", SessionEnvironment.ENV_PKL)) for env_pkl in env_pkls: session_env = SessionEnvironment.load_from_pkl( env_pkl, encryption_key) if session_env is not None: self._add_session_env(session_env) self.set_current(meta['current']) return self def get_container_id(self): try: with self.metadata.env_settings.open(mode='r') as f: settings = json.load(f) return settings.get('container_id', '') except FileNotFoundError: return '' def set_container_id(self, cid): with self.metadata.env_settings.open(mode='r') as f: settings = json.load(f) settings['container_id'] = cid self.metadata.env_settings.write(json.dumps(settings), 'w') def __str__(self): return "SessionManager(\n" \ " name={name}\n" \ " current_session={current}\n" \ " environment_location=\"{metadata}\"\n" \ " session_directory=\"{dir}\"\n" \ " container_id=\"{container_id}\")".format( name=self.name, metadata=str(self.metadata.env_settings.abspath), current=self.current_session, container_id=self.get_container_id(), dir=str(self.abspath) ) def __repr__(self): return "SessionManager(name={name}, env={env}".format( name=self.name, env=str(self.metadata.env_settings.abspath))
def test_unique_attrs(): env = ODir('bin') with pytest.raises(AttributeError): env.add('L1').add('L2') env.add('L1a').add('L2')
def test_chained(): env = ODir('bin') env.add('A1').add('B1') env.add('C1').add("D1")
def test_resolve(): env = ODir('bin') env.add('session1') env.session1.add('cat1') env.session1.add('cat2') print(env.paths.resolve)