Source code for pykindle.items

import os
from pykindle import readers


[docs]class FieldNotSetError(Exception): """ When user get a field of an item that has not been set yet, raise. """ def __init__(self, field): super(FieldNotSetError, self).__init__('{} not set.'.format(field))
[docs]class Item(dict): """ Item represents an asset of mobi files. This is a base class, you should inherit from it. Mobi file consists of several assets and a manifest. Each item renders to a asset, including articles, images and manifest files. Item class inherited from python dict class. You can set attributes in two ways: >>> item = Item() >>> item['href'] = 'path/to/item' >>> assert item.href == 'path/to/item' >>> item.href = 'path/to/item/changed' >>> assert item['href'] = 'path/to/item/changed' """ def __init__(self, *args, **kwargs): super(Item, self).__init__(*args, **kwargs) self._default = dict() def __getitem__(self, key): assert isinstance(key, str) if key in self: return super(Item, self).__getitem__(key) elif key in self._default: return self._default[key] else: raise FieldNotSetError(key) def __setitem__(self, key, value): super(Item, self).__setitem__(key, value) @property def href(self): """ Mobi file is just like a html website, and each asset has it's relative url in the mobi file. Html assets get other html assets and image assets by relative url. """ return self['href'] @href.setter def href(self, value): assert isinstance(value, str) self['href'] = value @property def media_type(self): """ Every mobi asset has a field to indicates what it is, for example, application/xhtml+xml represents an article, image/jpg represents a photo in jpg format. """ return self['media_type'] @media_type.setter def media_type(self, value): assert isinstance(value, str) assert '/' in value self['media_type'] = value @property def id(self): """ Id field should be a string! Not integer! Just like html elements has a "id" field, mobi assets also have such field. The difference is that in mobi assets, "id" field in required. """ return self['id'] @id.setter def id(self, value): assert isinstance(value, str) self['id'] = value @property def source(self): """ Source is the main content of the asset. It will later send to self.reader.render to get the rendered result. """ return self['source'] @source.setter def source(self, value): assert value is not None self['source'] = value @property def reader(self): """ Smetimes we need to convert some files to mobi supported assets. That's why we use reader. Reader should be a instance of pykindle.reader.Reader class. Item will call self.reader.render(self.source) to generate rendered assets. """ return self['reader'] @reader.setter def reader(self, value): assert isinstance(value, readers.Reader) self['reader'] = value @property def content(self): """ Readonly field. It just return the value of self.reader.render(self.source). """ return self.reader.render(self.source)
[docs] def write(self, directory): """ Write the rendered content to a file. File path is calculated by os.path.join(directory, self.href). """ path = os.path.join(directory, *self.href.split('/')) with open(path, mode='w', encoding='utf-8') as file: file.write(self.content)
[docs]class ArticleItem(Item): """ ArticleItem represents an real html article. This is the main body of your book. This class is used for inherit. Default attributes: title = Untitled author = No Author description = No description category = default """ def __init__(self, *args, **kwargs): super(ArticleItem, self).__init__(*args, **kwargs) self.media_type = 'application/xhtml+xml' self._default.update({ 'title': 'Untitled', 'author': 'No Author', 'description': 'No description.', 'category': 'default', }) @property def title(self): """ The title of article. """ return self['title'] @title.setter def title(self, value): assert isinstance(value, str) self['title'] = value @property def author(self): """ The author of article. """ return self['author'] @author.setter def author(self, value): assert isinstance(value, str) self['author'] = value @property def description(self): """ The description of article. """ return self['description'] @description.setter def description(self, value): assert isinstance(value, str) self['description'] = value @property def category(self): """ Optional. If you generates a magazine book, this field is used to calculate the magazine category. Deprecated. We will create a Category class to do this. :return: """ return self['category'] @category.setter def category(self, value): assert isinstance(value, str) self['category'] = value @property def content(self): return self.reader.render(self.title, self.author, self.description, self.source)
[docs]class HtmlArticleItem(ArticleItem): """ HtmlArticleItem represents a html article. Although all the articles in mobi files are html, we have other ArticleItem like MarkdownArticleItem to convert other formats to html. """ def __init__(self, *args, **kwargs): super(HtmlArticleItem, self).__init__(*args, **kwargs) self.reader = readers.HtmlReader()
[docs]class MarkdownArticleItem(ArticleItem): """ MarkdownArticleItem reads a markdown source. """ def __init__(self, *args, **kwargs): super(MarkdownArticleItem, self).__init__(*args, **kwargs) self.reader = readers.MarkdownReader()
[docs]class ImageItem(Item): """ ImageItem represents a image asset. It has a positional argument, image_format='jpeg', alternative formats are jpeg, png, gif """ def __init__(self, image_format='jpeg', *args, **kwargs): super(ImageItem, self).__init__(*args, **kwargs) assert image_format in ('jpeg', 'png', 'gif') self.image_format = image_format self.media_type = 'image/' + image_format self.reader = readers.ImageReader()
[docs]class CoverImageItem(ImageItem): """ CoverImageItem represents a cover image. """ pass
[docs]class NcxItem(Item): """ NcxItem is used to generate ncx file. Ncx file is the category of a book. It will be automatically added to the book when book.create is called. """ def __init__(self, *args, **kwargs): super(NcxItem, self).__init__(*args, **kwargs) self.media_type = 'application/x-dtbncx+xml' self._default.update({ 'id': 'ncx', 'href': 'ncx.toc', 'title': 'Untitled', 'author': 'No Author', }) @property def title(self): return self['title'] @title.setter def title(self, value): assert isinstance(value, str) self['title'] = value @property def author(self): return self['author'] @author.setter def author(self, value): assert isinstance(value, str) self['author'] = value
[docs]class MagazineNcxItem(NcxItem): """ MagazineNcxItem represents a magazine toc. The way to implement magazine is very ugly, and we'll reconstruct these classes. """ def __init__(self, *args, **kwargs): super(MagazineNcxItem, self).__init__(*args, **kwargs) self.reader = readers.MagazineNcxReader() @property def categories(self): return self['categories'] @categories.setter def categories(self, value): assert isinstance(value, list) for category, articles in value: if not isinstance(category, str): raise ValueError('category should be a string.') for article in articles: if not isinstance(article, ArticleItem): raise ValueError('article should be a pykindle.items.Article object') self['categories'] = value @property def content(self): return self.reader.render(title=self.title, author=self.author, categories=self.categories)
__all__ = ['Item', 'ArticleItem', 'HtmlArticleItem', 'MarkdownArticleItem', 'ImageItem', 'CoverImageItem', 'NcxItem', 'MagazineNcxItem', 'FieldNotSetError']