Example #1
0
 def __init__(self, name, eid, locs):
     BaseError.__init__(self, _('Duplicate id: %s') % eid, name)
     self.HELP = _(
         'The id {0} is present on more than one element in {1}. This is'
         ' not allowed. Remove the id from all but one of the elements').format(eid, name)
     self.all_locations = [(name, lnum, None) for lnum in sorted(locs)]
     self.duplicate_id = eid
Example #2
0
 def __init__(self, msg, *args, **kwargs):
     msg = msg or ''
     BaseError.__init__(self, 'Parsing failed: ' + msg, *args, **kwargs)
     m = mismatch_pat.search(msg)
     if m is not None:
         self.has_multiple_locations = True
         self.all_locations = [(self.name, int(m.group(1)), None), (self.name, self.line, self.col)]
Example #3
0
 def __init__(self, link_source, link_dest, link_elem, fragment):
     BaseError.__init__(self, _('Link points to a location not present in the target file'), link_source, line=link_elem.sourceline)
     self.bad_href = link_elem.get('href')
     self.HELP = _('The link "{0}" points to a location <i>{1}</i> in the file {2} that does not exist.'
                   ' You should either remove the location so that the link points to the top of the file,'
                   ' or change the link to point to the correct location.').format(
                       self.bad_href, fragment, link_dest)
Example #4
0
 def __init__(self, name, namespace):
     BaseError.__init__(self, _('Invalid or missing namespace'), name)
     self.HELP = prepare_string_for_xml(_(
         'This file has {0}. Its namespace must be {1}. Set the namespace by defining the xmlns'
         ' attribute on the <html> element, like this <html xmlns="{1}">').format(
             (_('incorrect namespace %s') % namespace) if namespace else _('no namespace'),
             XHTML_NS))
Example #5
0
 def __init__(self, font_name, css_name, name, line):
     BaseError.__init__(self, _('The CSS font-family name {0} does not match the actual font name {1}').format(css_name, font_name), name, line)
     self.HELP = _('The font family name specified in the CSS @font-face rule: "{0}" does'
                   ' not match the font name inside the actual font file: "{1}". This can'
                   ' cause problems in some viewers. You should change the CSS font name'
                   ' to match the actual font name.').format(css_name, font_name)
     self.INDIVIDUAL_FIX = _('Change the font name {0} to {1} everywhere').format(css_name, font_name)
     self.font_name, self.css_name = font_name, css_name
Example #6
0
 def __init__(self, name, lnum, bad_idref=None, bad_mimetype=None):
     if bad_idref is not None:
         msg = _('The item identified as the Table of Contents (%s) does not exist') % bad_idref
         self.HELP = _('There is no item with id="%s" in the manifest.') % bad_idref
     else:
         msg = _('The item identified as the Table of Contents has an incorrect media-type (%s)') % bad_mimetype
         self.HELP = _('The media type for the table of contents must be %s') % guess_type('a.ncx')
     BaseError.__init__(self, msg, name, lnum)
Example #7
0
 def __init__(self, name, line, eid):
     BaseError.__init__(self, _('Invalid id: %s') % eid, name, line)
     self.HELP = _(
         'The id {0} is not a valid id. IDs must start with a letter ([A-Za-z]) and may be'
         ' followed by any number of letters, digits ([0-9]), hyphens ("-"), underscores ("_")'
         ', colons (":"), and periods ("."). This is to ensure maximum compatibility'
         ' with a wide range of devices.').format(eid)
     self.invalid_id = eid
Example #8
0
 def __init__(self, link_source, link_dest, link_elem):
     BaseError.__init__(self, _('Link points to a file that is not a text document'), link_source, line=link_elem.sourceline)
     self.HELP = _('The link "{0}" points to a file <i>{1}</i> that is not a text (HTML) document.'
                   ' Many ebook readers will be unable to follow such a link. You should'
                   ' either remove the link or change it to point to a text document.'
                   ' For example, if it points to an image, you can create small wrapper'
                   ' document that contains the image and change the link to point to that.').format(
                       link_elem.get('href'), link_dest)
     self.bad_href = link_elem.get('href')
Example #9
0
 def __init__(self, container, name, opf_mt, ext_mt):
     self.opf_mt, self.ext_mt = opf_mt, ext_mt
     self.file_name = name
     BaseError.__init__(self, _('The file %s has a mimetype that does not match its extension') % name, container.opf_name)
     ext = name.rpartition('.')[-1]
     self.HELP = _('The file {0} has its mimetype specified as {1} in the OPF file.'
                   ' The recommended mimetype for files with the extension "{2}" is {3}.'
                   ' You should change either the file extension or the mimetype in the OPF.').format(
                       name, opf_mt, ext, ext_mt)
     self.INDIVIDUAL_FIX = _('Change the mimetype for this file in the OPF to %s') % ext_mt
Example #10
0
 def __init__(self, name, eid, locs, for_spine=False):
     loc = 'spine' if for_spine else 'manifest'
     BaseError.__init__(self, _('Duplicate item in {0}: {1}').format(loc, eid), name)
     self.HELP = _(
         'The item {0} is present more than once in the {2} in {1}. This is'
         ' not allowed.').format(eid, name, loc)
     self.all_locations = [(name, lnum, None) for lnum in sorted(locs)]
     self.duplicate_href = eid
     self.xpath = '/opf:package/opf:' + ('spine/opf:itemref[@idref]' if for_spine else 'manifest/opf:item[@href]')
     self.attr = 'idref' if for_spine else 'href'
Example #11
0
 def __init__(self, name, enc):
     BaseError.__init__(self, _("Non UTF-8 encoding declaration"), name)
     self.HELP = (
         _(
             "This file has its encoding declared as %s. Some"
             " reader software cannot handle non-UTF8 encoded files."
             " You should change the encoding to UTF-8."
         )
         % enc
     )
Example #12
0
 def __init__(self, name, iid, mt, lnum, opf_name):
     BaseError.__init__(self, _('Incorrect media-type for spine item'), opf_name, lnum)
     self.HELP = _(
         'The item {0} present in the spine has the media-type {1}. '
         ' Most ebook software cannot handle non-HTML spine items. '
         ' If the item is actually HTML, you should change its media-type to {2}.'
         ' If it is not-HTML you should consider replacing it with an HTML item, as it'
         ' is unlikely to work in most readers.').format(name, mt, XHTML_MIME)
     if iid is not None:
         self.INDIVIDUAL_FIX = _('Change the media-type to %s') % XHTML_MIME
         self.iid = iid
Example #13
0
    def __init__(self, name):
        BaseError.__init__(self, _('Filename contains unsafe characters'), name)
        qname = urlquote(name)

        self.sname = make_filename_safe(name)
        self.HELP = _(
            'The filename {0} contains unsafe characters, that must be escaped, like'
            ' this {1}. This can cause problems with some e-book readers. To be'
            ' absolutely safe, use only the English alphabet [a-z], the numbers [0-9],'
            ' underscores and hyphens in your file names. While many other characters'
            ' are allowed, they may cause problems with some software.').format(name, qname)
        self.INDIVIDUAL_FIX = _(
            'Rename the file {0} to {1}').format(name, self.sname)
Example #14
0
 def __init__(self, name):
     from calibre.utils.filenames import ascii_filename
     BaseError.__init__(self, _('Filename contains unsafe characters'), name)
     qname = urlquote(name)
     def esc(n):
         return ''.join(x if x in URL_SAFE else '_' for x in n)
     self.sname = '/'.join(esc(ascii_filename(x)) for x in name.split('/'))
     self.HELP = _(
         'The filename {0} contains unsafe characters, that must be escaped, like'
         ' this {1}. This can cause problems with some ebook readers. To be'
         ' absolutely safe, use only the English alphabet [a-z], the numbers [0-9],'
         ' underscores and hyphens in your file names. While many other characters'
         ' are allowed, they may cause problems with some software.').format(name, qname)
     self.INDIVIDUAL_FIX = _(
         'Rename the file {0} to {1}').format(name, self.sname)
Example #15
0
 def __init__(self, level, msg, name, line, col):
     self.level = level
     prefix = 'CSS: '
     BaseError.__init__(self, prefix + msg, name, line, col)
     if level == WARN:
         self.HELP = _('This CSS construct is not recognized. That means that it'
                       ' most likely will not work on reader devices. Consider'
                       ' replacing it with something else.')
     else:
         self.HELP = _('Some reader programs are very'
                       ' finicky about CSS stylesheets and will ignore the whole'
                       ' sheet if there is an error. These errors can often'
                       ' be fixed automatically, however, automatic fixing will'
                       ' typically remove unrecognized items, instead of correcting them.')
         self.INDIVIDUAL_FIX = _('Try to fix parsing errors in this stylesheet automatically')
Example #16
0
 def __init__(self, container, name, opf_mt, ext_mt):
     self.opf_mt, self.ext_mt = opf_mt, ext_mt
     self.file_name = name
     BaseError.__init__(
         self, _("The file %s has a mimetype that does not match its extension") % name, container.opf_name
     )
     ext = name.rpartition(".")[-1]
     self.HELP = _(
         "The file {0} has its mimetype specified as {1} in the OPF file."
         ' The recommended mimetype for files with the extension "{2}" is {3}.'
         " You should change either the file extension or the mimetype in the OPF."
     ).format(name, opf_mt, ext, ext_mt)
     if opf_mt in OEB_DOCS and name in {n for n, l in container.spine_names}:
         self.INDIVIDUAL_FIX = _("Change the file extension to .xhtml")
         self.change_ext_to = "xhtml"
     else:
         self.INDIVIDUAL_FIX = _("Change the mimetype for this file in the OPF to %s") % ext_mt
         self.change_ext_to = None
Example #17
0
 def __init__(self, container, name, opf_mt, ext_mt):
     self.opf_mt, self.ext_mt = opf_mt, ext_mt
     self.file_name = name
     BaseError.__init__(
         self,
         _('The file %s has a mimetype that does not match its extension') %
         name, container.opf_name)
     ext = name.rpartition('.')[-1]
     self.HELP = _(
         'The file {0} has its mimetype specified as {1} in the OPF file.'
         ' The recommended mimetype for files with the extension "{2}" is {3}.'
         ' You should change either the file extension or the mimetype in the OPF.'
     ).format(name, opf_mt, ext, ext_mt)
     if opf_mt in OEB_DOCS and name in {
             n
             for n, l in container.spine_names
     }:
         self.INDIVIDUAL_FIX = _('Change the file extension to .xhtml')
         self.change_ext_to = 'xhtml'
     else:
         self.INDIVIDUAL_FIX = _(
             'Change the mimetype for this file in the OPF to %s') % ext_mt
         self.change_ext_to = None
Example #18
0
 def __init__(self, name, enc):
     BaseError.__init__(self, _('Non UTF-8 encoding declaration'), name)
     self.HELP = _('This file has its encoding declared as %s. Some'
                   ' reader software cannot handle non-UTF8 encoded files.'
                   ' You should change the encoding to UTF-8.') % enc
Example #19
0
 def __init__(self, name, item_id, lnum):
     BaseError.__init__(self, _('Item in manifest has no href attribute'), name, lnum)
     self.item_id = item_id
Example #20
0
 def __init__(self, ent, name, lnum, col):
     BaseError.__init__(self, _('Invalid entity: %s') % ent, name, lnum, col)
Example #21
0
 def __init__(self, ent, name, lnum, col):
     BaseError.__init__(self, _('Invalid entity: %s') % ent, name, lnum, col)
Example #22
0
 def __init__(self, name, enc):
     BaseError.__init__(self, _('Non UTF-8 encoding declaration'), name)
     self.HELP = _('This file has its encoding declared as %s. Some'
                   ' reader software cannot handle non-UTF8 encoded files.'
                   ' You should change the encoding to UTF-8.') % enc
Example #23
0
 def __init__(self, name, idref, lnum):
     BaseError.__init__(self, _('idref="%s" points to unknown id') % idref, name, lnum)
     self.HELP = xml(_(
         'The idref="%s" points to an id that does not exist in the OPF') % idref)
Example #24
0
 def __init__(self, msg, *args, **kwargs):
     BaseError.__init__(self, 'Invalid image: ' + msg, *args, **kwargs)
Example #25
0
 def __init__(self, name):
     BaseError.__init__(self, _('The file %s is empty') % name, name)
Example #26
0
 def __init__(self, name):
     BaseError.__init__(self, _('Parsing of %s failed, could not decode') % name, name)
Example #27
0
 def __init__(self, name, lnum):
     BaseError.__init__(self, _('Empty identifier element'), name, lnum)
Example #28
0
 def __init__(self, name):
     BaseError.__init__(self, _('The file %s is empty') % name, name)
Example #29
0
 def __init__(self, name, section_name):
     BaseError.__init__(self, _('The <%s> section is missing from the OPF') % section_name, name)
     self.HELP = xml(_(
         'The <%s> section is required in the OPF file. You have to create one.') % section_name)
Example #30
0
 def __init__(self, name, href, lnum):
     BaseError.__init__(self, _('Item (%s) in manifest is missing') % href, name, lnum)
     self.bad_href = href
     self.INDIVIDUAL_FIX = _('Remove the entry for %s from the manifest') % href
Example #31
0
 def __init__(self, name, lnum):
     BaseError.__init__(self, _('Missing ToC in navigation document'), name, lnum)
Example #32
0
 def __init__(self, name, lnum, ncx_id):
     BaseError.__init__(self, _('Missing reference to the NCX Table of Contents'), name, lnum)
     self.ncx_id = ncx_id
Example #33
0
 def __init__(self, name, lnum, ncx_id):
     BaseError.__init__(self, _('Missing reference to the NCX Table of Contents'), name, lnum)
     self.ncx_id = ncx_id
Example #34
0
 def __init__(self, name, lines):
     BaseError.__init__(self, _('Bare text in body tag'), name)
     self.all_locations = [(name, l, None) for l in sorted(lines)]
Example #35
0
 def __init__(self, name):
     BaseError.__init__(self, _('Named entities present'), name)
Example #36
0
 def __init__(self, name):
     BaseError.__init__(self, _('Named entities present'), name)
Example #37
0
 def __init__(self, name, locs):
     BaseError.__init__(self, _('There is more than one cover defined'),
                        name)
     self.all_locations = [(name, lnum, None) for lnum in sorted(locs)]
Example #38
0
def check_opf(container):
    errors = []
    opf_version = container.opf_version_parsed

    if container.opf.tag != OPF('package'):
        err = BaseError(_('The OPF does not have the correct root element'), container.opf_name, container.opf.sourceline)
        err.HELP = xml(_(
            'The opf must have the root element <package> in namespace {0}, like this: <package xmlns="{0}">')).format(OPF2_NS)
        errors.append(err)

    elif container.opf.get('version') is None and container.book_type == 'epub':
        err = BaseError(_('The OPF does not have a version'), container.opf_name, container.opf.sourceline)
        err.HELP = xml(_(
            'The <package> tag in the OPF must have a version attribute. This is usually version="2.0" for EPUB2 and AZW3 and version="3.0" for EPUB3'))
        errors.append(err)

    for tag in ('metadata', 'manifest', 'spine'):
        if not container.opf_xpath('/opf:package/opf:' + tag):
            errors.append(MissingSection(container.opf_name, tag))

    all_ids = set(container.opf_xpath('//*/@id'))
    for elem in container.opf_xpath('//*[@idref]'):
        if elem.get('idref') not in all_ids:
            errors.append(IncorrectIdref(container.opf_name, elem.get('idref'), elem.sourceline))

    nl_items = [elem.sourceline for elem in container.opf_xpath('//opf:spine/opf:itemref[@linear="no"]')]
    if nl_items:
        errors.append(NonLinearItems(container.opf_name, nl_items))

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:manifest/opf:item'):
        href = item.get('href', None)
        if href is None:
            errors.append(NoHref(container.opf_name, item.get('id', None), item.sourceline))
        else:
            hname = container.href_to_name(href, container.opf_name)
            if not hname or not container.exists(hname):
                errors.append(MissingHref(container.opf_name, href, item.sourceline))
            if href in seen:
                if href not in dups:
                    dups[href] = [seen[href]]
                dups[href].append(item.sourceline)
            else:
                seen[href] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs) for eid, locs in dups.iteritems())

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:spine/opf:itemref[@idref]'):
        ref = item.get('idref')
        if ref in seen:
            if ref not in dups:
                dups[ref] = [seen[ref]]
            dups[ref].append(item.sourceline)
        else:
            seen[ref] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs, for_spine=True) for eid, locs in dups.iteritems())

    spine = container.opf_xpath('/opf:package/opf:spine[@toc]')
    if spine:
        spine = spine[0]
        mitems = [x for x in container.opf_xpath('/opf:package/opf:manifest/opf:item[@id]') if x.get('id') == spine.get('toc')]
        if mitems:
            mitem = mitems[0]
            if mitem.get('media-type', '') != guess_type('a.ncx'):
                errors.append(IncorrectToc(container.opf_name, mitem.sourceline, bad_mimetype=mitem.get('media-type')))
        else:
            errors.append(IncorrectToc(container.opf_name, spine.sourceline, bad_idref=spine.get('toc')))
    else:
        spine = container.opf_xpath('/opf:package/opf:spine')
        if spine:
            spine = spine[0]
            ncx = container.manifest_type_map.get(guess_type('a.ncx'))
            if ncx:
                ncx_name = ncx[0]
                rmap = {v:k for k, v in container.manifest_id_map.iteritems()}
                ncx_id = rmap.get(ncx_name)
                if ncx_id:
                    errors.append(MissingNCXRef(container.opf_name, spine.sourceline, ncx_id))

    if opf_version.major > 2:
        if find_existing_nav_toc(container) is None:
            errors.append(MissingNav(container.opf_name, 0))

    covers = container.opf_xpath('/opf:package/opf:metadata/opf:meta[@name="cover"]')
    if len(covers) > 0:
        if len(covers) > 1:
            errors.append(MultipleCovers(container.opf_name, [c.sourceline for c in covers]))
        manifest_ids = set(container.opf_xpath('/opf:package/opf:manifest/opf:item/@id'))
        for cover in covers:
            if cover.get('content', None) not in manifest_ids:
                errors.append(IncorrectCover(container.opf_name, cover.sourceline, cover.get('content', '')))
            raw = etree.tostring(cover)
            try:
                n, c = raw.index('name="'), raw.index('content="')
            except ValueError:
                n = c = -1
            if n > -1 and c > -1 and n > c:
                errors.append(NookCover(container.opf_name, cover.sourceline))

    uid = container.opf.get('unique-identifier', None)
    if uid is None or not container.opf_xpath('/opf:package/opf:metadata/dc:identifier[@id=%r]' % uid):
        errors.append(NoUID(container.opf_name))

    for item, name, linear in container.spine_iter:
        mt = container.mime_map[name]
        if mt != XHTML_MIME:
            iid = item.get('idref', None)
            lnum = None
            if iid:
                mitem = container.opf_xpath('/opf:package/opf:manifest/opf:item[@id=%r]' % iid)
                if mitem:
                    lnum = mitem[0].sourceline
                else:
                    iid = None
            errors.append(BadSpineMime(name, iid, mt, lnum, container.opf_name))

    return errors
Example #39
0
def check_opf(container):
    errors = []

    if container.opf.tag != OPF('package'):
        err = BaseError(_('The OPF does not have the correct root element'),
                        container.opf_name)
        err.HELP = xml(
            _('The opf must have the root element <package> in namespace {0}, like this: <package xmlns="{0}">'
              )).format(OPF2_NS)
        errors.append(err)

    for tag in ('metadata', 'manifest', 'spine'):
        if not container.opf_xpath('/opf:package/opf:' + tag):
            errors.append(MissingSection(container.opf_name, tag))

    all_ids = set(container.opf_xpath('//*/@id'))
    for elem in container.opf_xpath('//*[@idref]'):
        if elem.get('idref') not in all_ids:
            errors.append(
                IncorrectIdref(container.opf_name, elem.get('idref'),
                               elem.sourceline))

    nl_items = [
        elem.sourceline for elem in container.opf_xpath(
            '//opf:spine/opf:itemref[@linear="no"]')
    ]
    if nl_items:
        errors.append(NonLinearItems(container.opf_name, nl_items))

    seen, dups = {}, {}
    for item in container.opf_xpath(
            '/opf:package/opf:manifest/opf:item[@href]'):
        href = item.get('href')
        if not container.exists(
                container.href_to_name(href, container.opf_name)):
            errors.append(
                MissingHref(container.opf_name, href, item.sourceline))
        if href in seen:
            if href not in dups:
                dups[href] = [seen[href]]
            dups[href].append(item.sourceline)
        else:
            seen[href] = item.sourceline
    errors.extend(
        DuplicateHref(container.opf_name, eid, locs)
        for eid, locs in dups.iteritems())

    seen, dups = {}, {}
    for item in container.opf_xpath(
            '/opf:package/opf:spine/opf:itemref[@idref]'):
        ref = item.get('idref')
        if ref in seen:
            if ref not in dups:
                dups[ref] = [seen[ref]]
            dups[ref].append(item.sourceline)
        else:
            seen[ref] = item.sourceline
    errors.extend(
        DuplicateHref(container.opf_name, eid, locs, for_spine=True)
        for eid, locs in dups.iteritems())

    spine = container.opf_xpath('/opf:package/opf:spine[@toc]')
    if spine:
        spine = spine[0]
        mitems = [
            x for x in container.opf_xpath(
                '/opf:package/opf:manifest/opf:item[@id]')
            if x.get('id') == spine.get('toc')
        ]
        if mitems:
            mitem = mitems[0]
            if mitem.get('media-type', '') != guess_type('a.ncx'):
                errors.append(
                    IncorrectToc(container.opf_name,
                                 mitem.sourceline,
                                 bad_mimetype=mitem.get('media-type')))
        else:
            errors.append(
                IncorrectToc(container.opf_name,
                             spine.sourceline,
                             bad_idref=spine.get('toc')))

    covers = container.opf_xpath(
        '/opf:package/opf:metadata/opf:meta[@name="cover"]')
    if len(covers) > 0:
        if len(covers) > 1:
            errors.append(
                MultipleCovers(container.opf_name,
                               [c.sourceline for c in covers]))
        manifest_ids = set(
            container.opf_xpath('/opf:package/opf:manifest/opf:item/@id'))
        for cover in covers:
            if cover.get('content', None) not in manifest_ids:
                errors.append(
                    IncorrectCover(container.opf_name, cover.sourceline,
                                   cover.get('content', '')))
            raw = etree.tostring(cover)
            try:
                n, c = raw.index('name="'), raw.index('content="')
            except ValueError:
                n = c = -1
            if n > -1 and c > -1 and n > c:
                errors.append(NookCover(container.opf_name, cover.sourceline))

    uid = container.opf.get('unique-identifier', None)
    if uid is None or not container.opf_xpath(
            '/opf:package/opf:metadata/dc:identifier[@id=%r]' % uid):
        errors.append(NoUID(container.opf_name))

    for item, name, linear in container.spine_iter:
        mt = container.mime_map[name]
        if mt != XHTML_MIME:
            iid = item.get('idref', None)
            lnum = None
            if iid:
                mitem = container.opf_xpath(
                    '/opf:package/opf:manifest/opf:item[@id=%r]' % iid)
                if mitem:
                    lnum = mitem[0].sourceline
                else:
                    iid = None
            errors.append(BadSpineMime(name, iid, mt, lnum,
                                       container.opf_name))

    return errors
Example #40
0
 def __init__(self, name):
     BaseError.__init__(self, _('File too large'), name)
Example #41
0
File: fonts.py Project: yws/calibre
 def __init__(self, name, fs_type):
     BaseError.__init__(self, _('The font {} is not allowed to be embedded').format(name), name)
     self.HELP = _('The font has a flag in its metadata ({:09b}) set indicating that it is'
                   ' not licensed for embedding. You can ignore this warning, if you are'
                   ' sure you have permission to embed this font.').format(fs_type)
Example #42
0
 def __init__(self, name, lnum, cover):
     BaseError.__init__(self, _('The meta cover tag points to an non-existent item'), name, lnum)
     self.HELP = xml(_(
         'The meta cover tag points to an item with id="%s" which does not exist in the manifest') % cover)
Example #43
0
 def __init__(self, name):
     BaseError.__init__(self, _('File too large'), name)
Example #44
0
 def __init__(self, name):
     BaseError.__init__(self, _('Parsing of %s failed, could not decode') % name, name)
Example #45
0
 def __init__(self, name, lnum):
     BaseError.__init__(self, _('The meta cover tag has content before name'), name, lnum)
Example #46
0
 def __init__(self, name, lnum):
     BaseError.__init__(self, _('Empty id attributes are invalid'), name, lnum)
     self.HELP = xml(_(
         'Empty ID attributes are invalid in OPF files.'))
Example #47
0
 def __init__(self, msg, *args, **kwargs):
     BaseError.__init__(self, 'Parsing failed: ' + msg, *args, **kwargs)
Example #48
0
 def __init__(self, name, lines):
     BaseError.__init__(self, _('Bare text in body tag'), name)
     self.all_locations = [(name, l, None) for l in sorted(lines)]
Example #49
0
def check_opf(container):
    errors = []
    opf_version = container.opf_version_parsed

    if container.opf.tag != OPF('package'):
        err = BaseError(_('The OPF does not have the correct root element'), container.opf_name, container.opf.sourceline)
        err.HELP = xml(_(
            'The opf must have the root element <package> in namespace {0}, like this: <package xmlns="{0}">')).format(OPF2_NS)
        errors.append(err)

    elif container.opf.get('version') is None and container.book_type == 'epub':
        err = BaseError(_('The OPF does not have a version'), container.opf_name, container.opf.sourceline)
        err.HELP = xml(_(
            'The <package> tag in the OPF must have a version attribute. This is usually version="2.0" for EPUB2 and AZW3 and version="3.0" for EPUB3'))
        errors.append(err)

    for tag in ('metadata', 'manifest', 'spine'):
        if not container.opf_xpath('/opf:package/opf:' + tag):
            errors.append(MissingSection(container.opf_name, tag))

    all_ids = set(container.opf_xpath('//*/@id'))
    if '' in all_ids:
        for empty_id_tag in container.opf_xpath('//*[@id=""]'):
            errors.append(EmptyID(container.opf_name, empty_id_tag.sourceline))
    all_ids.discard('')
    for elem in container.opf_xpath('//*[@idref]'):
        if elem.get('idref') not in all_ids:
            errors.append(IncorrectIdref(container.opf_name, elem.get('idref'), elem.sourceline))

    nl_items = [elem.sourceline for elem in container.opf_xpath('//opf:spine/opf:itemref[@linear="no"]')]
    if nl_items:
        errors.append(NonLinearItems(container.opf_name, nl_items))

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:manifest/opf:item'):
        href = item.get('href', None)
        if href is None:
            errors.append(NoHref(container.opf_name, item.get('id', None), item.sourceline))
        else:
            hname = container.href_to_name(href, container.opf_name)
            if not hname or not container.exists(hname):
                errors.append(MissingHref(container.opf_name, href, item.sourceline))
            if href in seen:
                if href not in dups:
                    dups[href] = [seen[href]]
                dups[href].append(item.sourceline)
            else:
                seen[href] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs) for eid, locs in iteritems(dups))

    seen, dups = {}, {}
    for item in container.opf_xpath('/opf:package/opf:spine/opf:itemref[@idref]'):
        ref = item.get('idref')
        if ref in seen:
            if ref not in dups:
                dups[ref] = [seen[ref]]
            dups[ref].append(item.sourceline)
        else:
            seen[ref] = item.sourceline
    errors.extend(DuplicateHref(container.opf_name, eid, locs, for_spine=True) for eid, locs in iteritems(dups))

    spine = container.opf_xpath('/opf:package/opf:spine[@toc]')
    if spine:
        spine = spine[0]
        mitems = [x for x in container.opf_xpath('/opf:package/opf:manifest/opf:item[@id]') if x.get('id') == spine.get('toc')]
        if mitems:
            mitem = mitems[0]
            if mitem.get('media-type', '') != guess_type('a.ncx'):
                errors.append(IncorrectToc(container.opf_name, mitem.sourceline, bad_mimetype=mitem.get('media-type')))
        else:
            errors.append(IncorrectToc(container.opf_name, spine.sourceline, bad_idref=spine.get('toc')))
    else:
        spine = container.opf_xpath('/opf:package/opf:spine')
        if spine:
            spine = spine[0]
            ncx = container.manifest_type_map.get(guess_type('a.ncx'))
            if ncx:
                ncx_name = ncx[0]
                rmap = {v:k for k, v in iteritems(container.manifest_id_map)}
                ncx_id = rmap.get(ncx_name)
                if ncx_id:
                    errors.append(MissingNCXRef(container.opf_name, spine.sourceline, ncx_id))

    if opf_version.major > 2:
        existing_nav = find_existing_nav_toc(container)
        if existing_nav is None:
            errors.append(MissingNav(container.opf_name, 0))
        else:
            toc = parse_nav(container, existing_nav)
            if len(toc) == 0:
                errors.append(EmptyNav(existing_nav, 0))

    covers = container.opf_xpath('/opf:package/opf:metadata/opf:meta[@name="cover"]')
    if len(covers) > 0:
        if len(covers) > 1:
            errors.append(MultipleCovers(container.opf_name, [c.sourceline for c in covers]))
        manifest_ids = set(container.opf_xpath('/opf:package/opf:manifest/opf:item/@id'))
        for cover in covers:
            if cover.get('content', None) not in manifest_ids:
                errors.append(IncorrectCover(container.opf_name, cover.sourceline, cover.get('content', '')))
            raw = etree.tostring(cover)
            try:
                n, c = raw.index(b'name="'), raw.index(b'content="')
            except ValueError:
                n = c = -1
            if n > -1 and c > -1 and n > c:
                errors.append(NookCover(container.opf_name, cover.sourceline))

    uid = container.opf.get('unique-identifier', None)
    if uid is None or not container.opf_xpath('/opf:package/opf:metadata/dc:identifier[@id=%r]' % uid):
        errors.append(NoUID(container.opf_name))
    for elem in container.opf_xpath('/opf:package/opf:metadata/dc:identifier'):
        if not elem.text or not elem.text.strip():
            errors.append(EmptyIdentifier(container.opf_name, elem.sourceline))

    for item, name, linear in container.spine_iter:
        mt = container.mime_map[name]
        if mt != XHTML_MIME:
            iid = item.get('idref', None)
            lnum = None
            if iid:
                mitem = container.opf_xpath('/opf:package/opf:manifest/opf:item[@id=%r]' % iid)
                if mitem:
                    lnum = mitem[0].sourceline
                else:
                    iid = None
            errors.append(BadSpineMime(name, iid, mt, lnum, container.opf_name))

    return errors
Example #50
0
 def __init__(self, name, idref, lnum):
     BaseError.__init__(self, _('idref="%s" points to unknown id') % idref, name, lnum)
     self.HELP = xml(_(
         'The idref="%s" points to an id that does not exist in the OPF') % idref)
Example #51
0
 def __init__(self, name, lnum, cover):
     BaseError.__init__(self, _('The meta cover tag points to an non-existent item'), name, lnum)
     self.HELP = xml(_(
         'The meta cover tag points to an item with id="%s" which does not exist in the manifest') % cover)
Example #52
0
 def __init__(self, name, locs):
     BaseError.__init__(self, _('Non-linear items in the spine'), name)
     self.all_locations = [(name, x, None) for x in locs]
Example #53
0
 def __init__(self, name, item_id, lnum):
     BaseError.__init__(self, _('Item in manifest has no href attribute'), name, lnum)
     self.item_id = item_id
Example #54
0
 def __init__(self, name):
     BaseError.__init__(self, _('The OPF has no unique identifier'), name)
Example #55
0
 def __init__(self, msg, *args, **kwargs):
     BaseError.__init__(self, 'Invalid image: ' + msg, *args, **kwargs)
Example #56
0
 def __init__(self, name, lnum):
     BaseError.__init__(self,
                        _('The meta cover tag has content before name'),
                        name, lnum)
Example #57
0
 def __init__(self, msg, *args, **kwargs):
     BaseError.__init__(self, 'Parsing failed: ' + msg, *args, **kwargs)
     m = mismatch_pat.search(msg)
     if m is not None:
         self.has_multiple_locations = True
         self.all_locations = [(self.name, int(m.group(1)), None), (self.name, self.line, self.col)]