def filter_format(self, format, regex=False): """ Generator including all archive entries with a given format. Is regex=True, format will be compiled to a regular expression and matched against the entry formats """ if not format: raise KeyError('You need to provide an format') if regex is True: pattern = re.compile(format) else: pattern = None # check format argument against spec try: utils.check_format(format) except exceptions.CombineArchiveFormatException as e: raise KeyError( '{format} is no valid format, according to the OMEX specification. {cause}' .format(format=format, cause=e.message)) for (location, entry) in self.entries.items(): if pattern is not None and pattern.match(entry.format): yield entry elif pattern is None and format == entry.format: yield entry
def filter_format(self, format, regex=False): """ Generator including all archive entries with a given format. Is regex=True, format will be compiled to a regular expression and matched against the entry formats """ if not format: raise KeyError('You need to provide an format') if regex is True: pattern = re.compile(format) else: pattern = None # check format argument against spec try: utils.check_format(format) except exceptions.CombineArchiveFormatException as e: raise KeyError( '{format} is no valid format, according to the OMEX specification. {cause}'.format(format=format, cause=e.message)) for (location, entry) in self.entries.items(): if pattern is not None and pattern.match(entry.format): yield entry elif pattern is None and format == entry.format: yield entry
def _read_manifest(self): """ internal function. Reads the manifest file of a COMBINE Archive """ try: with self._zip.open(self.MANIFEST_LOCATION) as manifest_file: manifest = ElementTree.fromstring(manifest_file.read()) except KeyError: # manifest does not exists, probably an empty/new archive return False except ElementTree.ParseError as e: raise exceptions.CombineArchiveException( 'Cannot parse xml manifest. {}'.format(e.msg)) # check for correct root element and namespace if manifest.tag != utils.extend_tag_name(_XML_ROOT_ELEM, _XML_NS): raise exceptions.CombineArchiveException( 'manifest has no valid omex root element') # check entries for entry in manifest.findall(_XML_CONTENT_TAG, _XML_NS): try: location = utils.get_attribute(entry, _XML_CONTENT_LOCATION, _XML_NS) entry_format = utils.check_format(utils.get_attribute( entry, _XML_CONTENT_FORMAT, _XML_NS), convert=False) master = True if entry.attrib.get(_XML_CONTENT_MASTER, False) in ('True', 'true', True) else False except KeyError: raise exceptions.CombineArchiveException( 'location and format field are required. Corrupt manifest.xml' ) # clean location location = utils.clean_pathname(location) # check if file is in zip, if it's not the root element zipinfo = None if location not in self.ARCHIVE_REFERENCE: try: zipinfo = self._zip.getinfo(location) except KeyError: raise exceptions.CombineArchiveException( '{location} is specified by the manifest, but not contained by the ZIP file' .format(location=location)) archive_entry = ArchiveEntry(location, format=entry_format, master=master, archive=self, zipinfo=zipinfo) self.entries[location] = archive_entry
def add_entry(self, file, format, location=None, master=False, replace=False): """ adds a file-like object to the COMBINE archive and adds a manifest entry if file is an instance of unicode or str, the content of this variable is written as content Returns: ArchiveEntry """ if not file or not format: raise exceptions.CombineArchiveException( 'both a file and the corresponding format must be provided') # check format schema format = utils.check_format(format) # no location provided. Guess it if location is None or not location: location = os.path.basename(file) # clean location location = utils.clean_pathname(location) if location == self.MANIFEST_LOCATION or location in self.ARCHIVE_REFERENCE: raise exceptions.CombineArchiveException( 'it is not allowed to name a file {loc}'.format(loc=location)) if location in self._zip.namelist(): if replace is False: raise exceptions.CombineArchiveException( '{loc} exists already in the COMBINE archive. set replace=True, to override it' .format(loc=location)) else: self.remove_entry(location) # write file to zip if isinstance(file, (str, unicode)): # file is actually string zipinfo = self._zip.writestr(location, file) else: zipinfo = self._zip.write(file, location) entry = ArchiveEntry(location, format=format, master=master, zipinfo=zipinfo, archive=self) self.entries[entry.location] = entry return entry
def _write_manifest(self, zip_file=None): """ internal function. Writes the manifest file of a COMBINE Archive """ if zip_file is None: zip_file = self._zip # create new DOM object manifest = ElementTree.Element( utils.extend_tag_name(_XML_ROOT_ELEM, _XML_NS)) # write first entry for archive itself content = ElementTree.SubElement( manifest, utils.extend_tag_name(_XML_CONTENT_TAG, _XML_NS)) content.attrib.update({ utils.extend_tag_name(_XML_CONTENT_LOCATION, _XML_NS): '.', utils.extend_tag_name(_XML_CONTENT_FORMAT, _XML_NS): _XML_CONTENT_ARCHIVE_TYPE, }) for (location, entry) in self.entries.items(): entry_format = utils.check_format(entry.format) content = ElementTree.SubElement( manifest, utils.extend_tag_name(_XML_CONTENT_TAG, _XML_NS)) content.attrib.update({ utils.extend_tag_name(_XML_CONTENT_LOCATION, _XML_NS): location, utils.extend_tag_name(_XML_CONTENT_FORMAT, _XML_NS): entry_format, }) if entry.master: content.attrib[utils.extend_tag_name(_XML_CONTENT_MASTER, _XML_NS)] = 'true' # write xml to zip io = StringIO() ElementTree.ElementTree(manifest).write(io, xml_declaration=True, default_namespace=_XML_ROOT_NS) try: zip_file.remove(self.MANIFEST_LOCATION) except KeyError: pass # Manifest does not exist yet, so removing it will fail zip_file.writestr(self.MANIFEST_LOCATION, io.getvalue()) io.close()
def _read_manifest(self): """ internal function. Reads the manifest file of a COMBINE Archive """ try: with self._zip.open(self.MANIFEST_LOCATION) as manifest_file: manifest = ElementTree.fromstring(manifest_file.read()) except KeyError: # manifest does not exists, probably an empty/new archive return False except ElementTree.ParseError as e: raise exceptions.CombineArchiveException('Cannot parse xml manifest. {}'.format(e.msg)) # check for correct root element and namespace if manifest.tag != utils.extend_tag_name(_XML_ROOT_ELEM, _XML_NS): raise exceptions.CombineArchiveException('manifest has no valid omex root element') # check entries for entry in manifest.findall(_XML_CONTENT_TAG, _XML_NS): try: location = utils.get_attribute(entry, _XML_CONTENT_LOCATION, _XML_NS) entry_format = utils.check_format(utils.get_attribute(entry, _XML_CONTENT_FORMAT, _XML_NS), convert=False) master = True if entry.attrib.get(_XML_CONTENT_MASTER, False) in ('True', 'true', True) else False except KeyError: raise exceptions.CombineArchiveException('location and format field are required. Corrupt manifest.xml') # clean location location = utils.clean_pathname(location) # check if file is in zip, if it's not the root element zipinfo = None if location not in self.ARCHIVE_REFERENCE: try: zipinfo = self._zip.getinfo(location) except KeyError: raise exceptions.CombineArchiveException( '{location} is specified by the manifest, but not contained by the ZIP file'.format(location=location)) archive_entry = ArchiveEntry(location, format=entry_format, master=master, archive=self, zipinfo=zipinfo) self.entries[location] = archive_entry
def add_entry(self, file, format, location=None, master=False, replace=False): """ adds a file-like object to the COMBINE archive and adds a manifest entry if file is an instance of unicode or str, the content of this variable is written as content Returns: ArchiveEntry """ if not file or not format: raise exceptions.CombineArchiveException('both a file and the corresponding format must be provided') # check format schema format = utils.check_format(format) # no location provided. Guess it if location is None or not location: location = os.path.basename(file) # clean location location = utils.clean_pathname(location) if location == self.MANIFEST_LOCATION or location in self.ARCHIVE_REFERENCE: raise exceptions.CombineArchiveException('it is not allowed to name a file {loc}'.format(loc=location)) if location in self._zip.namelist(): if replace is False: raise exceptions.CombineArchiveException('{loc} exists already in the COMBINE archive. set replace=True, to override it'.format(loc=location)) else: self.remove_entry(location) # write file to zip if isinstance(file, (str, unicode)): # file is actually string zipinfo = self._zip.writestr(location, file) else: zipinfo = self._zip.write(file, location) entry = ArchiveEntry(location, format=format, master=master, zipinfo=zipinfo, archive=self) self.entries[entry.location] = entry return entry
def _write_manifest(self, zip_file=None): """ internal function. Writes the manifest file of a COMBINE Archive """ if zip_file is None: zip_file = self._zip # create new DOM object manifest = ElementTree.Element(utils.extend_tag_name(_XML_ROOT_ELEM, _XML_NS)) # write first entry for archive itself content = ElementTree.SubElement(manifest, utils.extend_tag_name(_XML_CONTENT_TAG, _XML_NS)) content.attrib.update({ utils.extend_tag_name(_XML_CONTENT_LOCATION, _XML_NS): '.', utils.extend_tag_name(_XML_CONTENT_FORMAT, _XML_NS): _XML_CONTENT_ARCHIVE_TYPE, }) for (location, entry) in self.entries.items(): entry_format = utils.check_format(entry.format) content = ElementTree.SubElement(manifest, utils.extend_tag_name(_XML_CONTENT_TAG, _XML_NS)) content.attrib.update({ utils.extend_tag_name(_XML_CONTENT_LOCATION, _XML_NS): location, utils.extend_tag_name(_XML_CONTENT_FORMAT, _XML_NS): entry_format, }) if entry.master: content.attrib[utils.extend_tag_name(_XML_CONTENT_MASTER, _XML_NS)] = 'true' # write xml to zip io = StringIO() ElementTree.ElementTree(manifest).write(io, xml_declaration=True, default_namespace=_XML_ROOT_NS) try: zip_file.remove(self.MANIFEST_LOCATION) except KeyError: pass # Manifest does not exist yet, so removing it will fail zip_file.writestr(self.MANIFEST_LOCATION, io.getvalue()) io.close()