All libraries should implement this."""
raise NotImplementedError()
+ def byid(self, id):
+ """Returns a previously known manga by its string ID, or
+ raises KeyError if no such manga could be found.
+
+ All libraries should implement this."""
+ raise KeyError(id)
+
def __iter__(self):
"""Return an iterator of all known mangas in this library.
class pagetree(object):
"""Base class for objects in the tree of pages and pagelists.
- All pagetree objects should contain an attribute `stack', contains
- a list of pairs. The last pair in the list should be the pagetree
- object which yielded this pagetree object, along with the index
- which yielded it. Every non-last pair should be the same
+ All pagetree objects should contain an attribute `stack',
+ containing a list of pairs. The last pair in the list should be
+ the pagetree object which yielded this pagetree object, along with
+ the index which yielded it. Every non-last pair should be the same
information for the pair following it. The only objects with empty
- `stack' lists should be `manga' objects."""
- pass
+ `stack' lists should be `manga' objects.
+
+ All non-root pagetree objects should also contain an attribute
+ `id', which should be a string that can be passed to the `byid'
+ function of its parent node to recover the node. Such string ID
+ should be more persistent than the node's numeric index in the
+ parent.
+
+ All pagetree objects should contain an attribute `name',
+ containing some human-readable Unicode representation of the
+ pagelist."""
+
+ def idlist(self):
+ """Returns a list of the IDs necessary to resolve this node
+ from the root node."""
+ if len(self.stack) == 0:
+ return []
+ return self.stack[-1][0].idlist() + [self.id]
+
+ def byidlist(self, idlist):
+ if len(idlist) == 0:
+ return self
+ return self.byid(idlist[0]).byidlist(idlist[1:])
class pagelist(pagetree):
"""Class representing a list of either pages, or nested
- pagelists. Might be, for instance, a volume or a chapter.
-
- All pagelists should contain an attribute `name', containing some
- human-readable Unicode representation of the pagelist."""
+ pagelists. Might be, for instance, a volume or a chapter."""
def __len__(self):
"""Return the number of (direct) sub-nodes in this pagelist.
All pagelists need to implement this."""
raise NotImplementedError()
+ def byid(self, id):
+ """Return the direct sub-node of this pagelist which has the
+ given string ID. If none is found, a KeyError is raised.
+
+ This default method iterates the children of this node, but
+ may be overridden by some more efficient implementation.
+ """
+ for ch in self:
+ if ch.id == id:
+ return ch
+ raise KeyError(id)
+
class manga(pagelist):
"""Class reprenting a single manga. Includes the pagelist class,
- and all constraints valid for it."""
+ and all constraints valid for it.
+
+ A manga is a root pagetree node, but should also contain an `id'
+ attribute, which can be used to recover the manga from its
+ library's `byid' function."""
pass
class page(pagetree):
when exiting the with-scope.
All imgstreams should contain an attribute `ctype', being the
- Content-Type of the image being read by the stream."""
+ Content-Type of the image being read by the stream, and `clen`,
+ being either an int describing the total number of bytes in the
+ stream, or None if the value is not known in advance."""
def __enter__(self):
return self
def __exit__(self, *exc_info):
self.close()
+ def fileno(self):
+ """If reading the imgstream may block, fileno() should return
+ a file descriptor that can be polled. If fileno() returns
+ None, that should mean that reading will not block."""
+ return None
+
def close(self):
"""Close this stream."""
raise NotImplementedError()
stream of SZ is not given."""
raise NotImplementedError()
-class pageiter(object):
- def __init__(self, root):
- self.nstack = [0]
- self.lstack = [root]
+class cursor(object):
+ def __init__(self, ob):
+ if isinstance(ob, cursor):
+ self.cur = ob.cur
+ else:
+ self.cur = self.descend(ob)
+
+ def descend(self, ob):
+ while isinstance(ob, pagelist):
+ ob = ob[0]
+ if not isinstance(ob, page):
+ raise TypeError("object in page tree was unexpectedly not a pagetree")
+ return ob
def next(self):
- while True:
- if len(self.nstack) == 0:
- raise StopIteration
- try:
- node = self.lstack[-1][self.nstack[-1]]
- except IndexError:
- self.lstack.pop()
- self.nstack.pop()
- if len(self.nstack) > 0:
- self.nstack[-1] += 1
- continue
- if isinstance(node, page):
- nl = tuple(self.nstack)
- self.nstack[-1] += 1
- return nl, node
- elif isinstance(node, pagelist):
- self.lstack.append(node)
- self.nstack.append(0)
+ for n, i in reversed(self.cur.stack):
+ if i < len(n) - 1:
+ self.cur = self.descend(n[i + 1])
+ return self.cur
+ raise StopIteration()
+
+ def prev(self):
+ for n, i in reversed(self.cur.stack):
+ if i > 0:
+ self.cur = self.descend(n[i - 1])
+ return self.cur
+ raise StopIteration()
def __iter__(self):
return self
+
+def _lazymod(name):
+ return __import__(name, fromlist=["dummy"])
+class _lazydict(object):
+ def __init__(self):
+ self.bk = {}
+ def __setitem__(self, key, val):
+ self.bk[key] = "u", val
+ def __getitem__(self, key):
+ st, v = self.bk[key]
+ if st == "u":
+ v = self.bk[key] = v()
+ return v
+libraries = _lazydict()
+libraries["mf"] = lambda: _lazymod("manga.mangafox").library()