def __init__(self, archive_path: Path): self._backup_glob = None self._backup_retention = 0 self._compression = zf.ZIP_DEFLATED self._archive_cache: Dict[str, bytes] = {} self._archive_path = archive_path self._archive_members: Set[str] = set() if not archive_path.exists(): log.warning(f'{archive_path} not found, creating...') # opening the archive will create it if it doesn't already exist try: with self._get_writable_zipfile(): pass except Exception as exc: raise err.WeatherDataError(f'Yikes... Error opening "{str(Path)}": {str(exc)}') else: try: with self._get_readable_zipfile() as zipfile: for name in zipfile.namelist(): # verify there are no duplicate histories in the archive if name in self._archive_members: raise err.WeatherDataError(f'Yikes... Found duplicate weather history: {name}') self._archive_members.add(name) except err.WeatherDataError: pass except Exception as exc: raise err.WeatherDataError(f'Yikes... Error reading archive name list: {str(exc)}')
def reader_(data_path: DataPath) -> DataContent: full_path = Path(self._dir_path, data_path) if not full_path.exists(): raise err.WeatherDataError("Yikes... '{}' was not found!".format(data_path)) elif not full_path.is_file(): raise err.WeatherDataError("Yikes... '{}' is not a data file!".format(data_path)) with full_path.open('r+b') as fp: return fp.read()
def writer(self) -> DataSourceWriter: # the backup archive only exists as long as the writer is active but jic... backup_archive: Path = self._archive_path.with_suffix(".bck") backup_archive.unlink(missing_ok=True) shutil.copy2(str(self._archive_path), str(backup_archive)) with self._get_writable_zipfile(self._archive_path) as writable_zipfile: try: def write_function(data_path: DataPath, content: DataContent): data_path = str(data_path) if isinstance(data_path, Path) else data_path if data_path in self._archive_members: raise err.WeatherDataError("'{}' already exists...".format(data_path)) zip_info = zf.ZipInfo(data_path, datetime.today().timetuple()[:-3]) zip_info.compress_type = zf.ZIP_DEFLATED writable_zipfile.writestr(zip_info, content) self._archive_members.add(data_path) yield write_function except Exception as error: exception = err.WeatherDataError("Yikes!!! Error adding entry: {}".format(error)) raise exception.with_traceback(sys.exc_info()[2]) else: backup_archive.unlink() finally: # clean up the backup if it exists at this point, there was an error if backup_archive.exists(): self._archive_path.unlink() backup_archive.rename(self._archive_path)
def write_function(data_path: DataPath, content: DataContent): data_path = str(data_path) if isinstance(data_path, Path) else data_path if data_path in self._archive_members: raise err.WeatherDataError("'{}' already exists...".format(data_path)) zip_info = zf.ZipInfo(data_path, datetime.today().timetuple()[:-3]) zip_info.compress_type = zf.ZIP_DEFLATED writable_zipfile.writestr(zip_info, content) self._archive_members.add(data_path)
def __init__(self, data_path: DataPath, make_if_not_found: bool = True, encoding="UTF-8"): self._dir_path = data_path if isinstance(data_path, Path) else Path(data_path) self._encoding = encoding if not self._dir_path.exists(): if make_if_not_found: self._dir_path.mkdir(parents=True) else: log.warning("'{}' does not exist...".format(data_path)) elif not self._dir_path.is_dir(): raise err.WeatherDataError("Yikes... '{}' is not a directory!".format(self._dir_path))
def __init__(self, dir_ds: DirectoryDataSource, locations_path: DataPath = Path("locations.json")): self._locations: List[Location] = [] self._dirty: bool = False self._dir_ds = dir_ds self._locations_path = locations_path if isinstance(locations_path, Path) else Path(locations_path) if dir_ds.exists(locations_path): with dir_ds.reader() as read_locations: locations_dict = json.loads(read_locations(locations_path)) locations = locations_dict.get(self.DICT_ROOT) if not locations: log.warning("Locations root '{}' was not found in '{}'".format(self.DICT_ROOT, locations_path)) else: for location_dict in locations: location = Location.from_dict(location_dict) if location in self._locations: raise err.WeatherDataError("Duplicate location in '{}': name='{}' alias='{}'" .format(self.DICT_ROOT, location.name, location.alias)) self._locations.append(location)
def add(self, location: Location): if 0 <= self._index_of(location): raise err.WeatherDataError("'{}' already exists!!!".format(location.name)) self._locations.append(location) self._dirty = True