# HG changeset patch # User Paul Boddie # Date 1383745230 -3600 # Node ID 0cccc791aac263b80ce46ed9990c5321f34b6bdf # Parent 14b1c0fbe11cda2f3eccbeb0643de57f393cbc51 Moved ItemStore and related functionality into ItemSupport. Updated release details. diff -r 14b1c0fbe11c -r 0cccc791aac2 ItemSupport.py --- a/ItemSupport.py Wed Nov 06 12:41:01 2013 +0100 +++ b/ItemSupport.py Wed Nov 06 14:40:30 2013 +0100 @@ -6,11 +6,16 @@ @license: GNU GPL (v2 or later), see COPYING.txt for details. """ +from MoinMoin.Page import Page, RootPage +from MoinMoin.PageEditor import PageEditor from MoinMoin.util import lock +import re import os # Content storage support. +# Underlying storage mechanisms. + class GeneralItemStore: "Common item store functionality." @@ -208,6 +213,98 @@ finally: self.writelock.release() +class SubpageItemStore(GeneralItemStore): + + "A subpage-based item store." + + def __init__(self, page, lock_dir): + + "Initialise an item store for subpages under the given 'page'." + + GeneralItemStore.__init__(self, lock_dir) + self.page = page + + def mtime(self): + + "Return the last modified time of the item store." + + keys = self.get_keys() + if not keys: + page = self.page + else: + page = Page(self.page.request, self.get_item_path(max(keys))) + + return wikiutil.version2timestamp( + getMetadata(page)["last-modified"] + ) + + def get_next(self): + + "Return the next item number." + + return self.deduce_next() + + def get_keys(self): + + "Return the item keys." + + is_subpage = re.compile(u"^%s/" % re.escape(self.page.page_name), re.UNICODE).match + + # Collect the strict subpages of the parent page. + + leafnames = [] + parentname = self.page.page_name + + for pagename in RootPage(self.page.request).getPageList(filter=is_subpage): + parts = pagename[len(parentname)+1:].split("/") + + # Only collect numbered pages immediately below the parent. + + if len(parts) == 1 and parts[0].isdigit(): + leafnames.append(int(parts[0])) + + return leafnames + + def write_item(self, item, next): + + "Write the given 'item' to a file with the given 'next' item number." + + page = PageEditor(self.page.request, self.get_item_path(next)) + page.saveText(item, 0) + + def read_item(self, number): + + "Read the item with the given item 'number'." + + page = Page(self.page.request, self.get_item_path(number)) + return page.get_raw_body() + + def remove_item(self, number): + + "Remove the item with the given item 'number'." + + page = PageEditor(self.page.request, self.get_item_path(number)) + page.deletePage() + + def get_item_path(self, number): + + "Get the path for the given item 'number'." + + return "%s/%s" % (self.page.page_name, number) + + # High-level methods. + + def append(self, item): + + "Append the given 'item' to the store." + + self.writelock.acquire() + try: + next = self.get_next() + self.write_item(item, next) + finally: + self.writelock.release() + class ItemIterator: "An iterator over items in a store." @@ -256,4 +353,139 @@ def __iter__(self): return self +def getDirectoryItemStoreForPage(page, item_dir, lock_dir): + + """ + A convenience function returning a directory-based store for the given + 'page', using the given 'item_dir' and 'lock_dir'. + """ + + item_dir_path = tuple(item_dir.split("/")) + lock_dir_path = tuple(lock_dir.split("/")) + return DirectoryItemStore(page.getPagePath(*item_dir_path), page.getPagePath(*lock_dir_path)) + +def getSubpageItemStoreForPage(page, lock_dir): + + """ + A convenience function returning a subpage-based store for the given + 'page', using the given 'lock_dir'. + """ + + lock_dir_path = tuple(lock_dir.split("/")) + return SubpageItemStore(page, page.getPagePath(*lock_dir_path)) + +# Page-oriented item store classes. + +class ItemStoreBase: + + "Access item stores via pages, observing page access restrictions." + + def __init__(self, page, store): + self.page = page + self.store = store + + def can_write(self): + + """ + Return whether the user associated with the request can write to the + page owning this store. + """ + + user = self.page.request.user + return user and user.may.write(self.page.page_name) + + def can_read(self): + + """ + Return whether the user associated with the request can read from the + page owning this store. + """ + + user = self.page.request.user + return user and user.may.read(self.page.page_name) + + def can_delete(self): + + """ + Return whether the user associated with the request can delete the + page owning this store. + """ + + user = self.page.request.user + return user and user.may.delete(self.page.page_name) + + # Store-specific methods. + + def mtime(self): + return self.store.mtime() + + # High-level methods. + + def keys(self): + + "Return a list of keys for items in the store." + + if not self.can_read(): + return 0 + + return self.store.keys() + + def append(self, item): + + "Append the given 'item' to the store." + + if not self.can_write(): + return + + self.store.append(item) + + def __len__(self): + + "Return the number of items in the store." + + if not self.can_read(): + return 0 + + return len(self.store) + + def __getitem__(self, number): + + "Return the item with the given 'number'." + + if not self.can_read(): + raise IndexError, number + + return self.store.__getitem__(number) + + def __delitem__(self, number): + + "Remove the item with the given 'number'." + + if not self.can_delete(): + return + + return self.store.__delitem__(number) + + def __iter__(self): + return self.store.__iter__() + + def next(self): + return self.store.next() + +# Convenience store classes. + +class ItemStore(ItemStoreBase): + + "Store items in a directory via a page." + + def __init__(self, page, item_dir="items", lock_dir="item_locks"): + ItemStoreBase.__init__(self, page, getDirectoryItemStoreForPage(page, item_dir, lock_dir)) + +class ItemSubpageStore(ItemStoreBase): + + "Store items in subpages of a page." + + def __init__(self, page, lock_dir="item_locks"): + ItemStoreBase.__init__(self, page, getSubpageItemStoreForPage(page, lock_dir)) + # vim: tabstop=4 expandtab shiftwidth=4 diff -r 14b1c0fbe11c -r 0cccc791aac2 MoinSupport.py --- a/MoinSupport.py Wed Nov 06 12:41:01 2013 +0100 +++ b/MoinSupport.py Wed Nov 06 14:40:30 2013 +0100 @@ -13,11 +13,8 @@ """ from DateSupport import * -from ItemSupport import DirectoryItemStore, GeneralItemStore from MoinMoin.parser import text_moin_wiki -from MoinMoin.Page import Page, RootPage -from MoinMoin.PageEditor import PageEditor -from MoinMoin.util import lock +from MoinMoin.Page import Page from MoinMoin import config, search, wikiutil from shlex import shlex import re @@ -37,7 +34,7 @@ except ImportError: pass -__version__ = "0.4.1" +__version__ = "0.4.2" # Extraction of shared fragments. @@ -1091,235 +1088,4 @@ else: return title -# Content storage support. - -# Underlying storage mechanisms. - -class SubpageItemStore(GeneralItemStore): - - "A subpage-based item store." - - def __init__(self, page, lock_dir): - - "Initialise an item store for subpages under the given 'page'." - - GeneralItemStore.__init__(self, lock_dir) - self.page = page - - def mtime(self): - - "Return the last modified time of the item store." - - keys = self.get_keys() - if not keys: - page = self.page - else: - page = Page(self.page.request, self.get_item_path(max(keys))) - - return wikiutil.version2timestamp( - getMetadata(page)["last-modified"] - ) - - def get_next(self): - - "Return the next item number." - - return self.deduce_next() - - def get_keys(self): - - "Return the item keys." - - is_subpage = re.compile(u"^%s/" % re.escape(self.page.page_name), re.UNICODE).match - - # Collect the strict subpages of the parent page. - - leafnames = [] - parentname = self.page.page_name - - for pagename in RootPage(self.page.request).getPageList(filter=is_subpage): - parts = pagename[len(parentname)+1:].split("/") - - # Only collect numbered pages immediately below the parent. - - if len(parts) == 1 and parts[0].isdigit(): - leafnames.append(int(parts[0])) - - return leafnames - - def write_item(self, item, next): - - "Write the given 'item' to a file with the given 'next' item number." - - page = PageEditor(self.page.request, self.get_item_path(next)) - page.saveText(item, 0) - - def read_item(self, number): - - "Read the item with the given item 'number'." - - page = Page(self.page.request, self.get_item_path(number)) - return page.get_raw_body() - - def remove_item(self, number): - - "Remove the item with the given item 'number'." - - page = PageEditor(self.page.request, self.get_item_path(number)) - page.deletePage() - - def get_item_path(self, number): - - "Get the path for the given item 'number'." - - return "%s/%s" % (self.page.page_name, number) - - # High-level methods. - - def append(self, item): - - "Append the given 'item' to the store." - - self.writelock.acquire() - try: - next = self.get_next() - self.write_item(item, next) - finally: - self.writelock.release() - -def getDirectoryItemStoreForPage(page, item_dir, lock_dir): - - """ - A convenience function returning a directory-based store for the given - 'page', using the given 'item_dir' and 'lock_dir'. - """ - - item_dir_path = tuple(item_dir.split("/")) - lock_dir_path = tuple(lock_dir.split("/")) - return DirectoryItemStore(page.getPagePath(*item_dir_path), page.getPagePath(*lock_dir_path)) - -def getSubpageItemStoreForPage(page, lock_dir): - - """ - A convenience function returning a subpage-based store for the given - 'page', using the given 'lock_dir'. - """ - - lock_dir_path = tuple(lock_dir.split("/")) - return SubpageItemStore(page, page.getPagePath(*lock_dir_path)) - -# Page-oriented item store classes. - -class ItemStoreBase: - - "Access item stores via pages, observing page access restrictions." - - def __init__(self, page, store): - self.page = page - self.store = store - - def can_write(self): - - """ - Return whether the user associated with the request can write to the - page owning this store. - """ - - user = self.page.request.user - return user and user.may.write(self.page.page_name) - - def can_read(self): - - """ - Return whether the user associated with the request can read from the - page owning this store. - """ - - user = self.page.request.user - return user and user.may.read(self.page.page_name) - - def can_delete(self): - - """ - Return whether the user associated with the request can delete the - page owning this store. - """ - - user = self.page.request.user - return user and user.may.delete(self.page.page_name) - - # Store-specific methods. - - def mtime(self): - return self.store.mtime() - - # High-level methods. - - def keys(self): - - "Return a list of keys for items in the store." - - if not self.can_read(): - return 0 - - return self.store.keys() - - def append(self, item): - - "Append the given 'item' to the store." - - if not self.can_write(): - return - - self.store.append(item) - - def __len__(self): - - "Return the number of items in the store." - - if not self.can_read(): - return 0 - - return len(self.store) - - def __getitem__(self, number): - - "Return the item with the given 'number'." - - if not self.can_read(): - raise IndexError, number - - return self.store.__getitem__(number) - - def __delitem__(self, number): - - "Remove the item with the given 'number'." - - if not self.can_delete(): - return - - return self.store.__delitem__(number) - - def __iter__(self): - return self.store.__iter__() - - def next(self): - return self.store.next() - -# Convenience store classes. - -class ItemStore(ItemStoreBase): - - "Store items in a directory via a page." - - def __init__(self, page, item_dir="items", lock_dir="item_locks"): - ItemStoreBase.__init__(self, page, getDirectoryItemStoreForPage(page, item_dir, lock_dir)) - -class ItemSubpageStore(ItemStoreBase): - - "Store items in subpages of a page." - - def __init__(self, page, lock_dir="item_locks"): - ItemStoreBase.__init__(self, page, getSubpageItemStoreForPage(page, lock_dir)) - # vim: tabstop=4 expandtab shiftwidth=4 diff -r 14b1c0fbe11c -r 0cccc791aac2 PKG-INFO --- a/PKG-INFO Wed Nov 06 12:41:01 2013 +0100 +++ b/PKG-INFO Wed Nov 06 14:40:30 2013 +0100 @@ -1,12 +1,12 @@ Metadata-Version: 1.1 Name: MoinSupport -Version: 0.4.1 +Version: 0.4.2 Author: Paul Boddie Author-email: paul at boddie org uk Maintainer: Paul Boddie Maintainer-email: paul at boddie org uk Home-page: http://hgweb.boddie.org.uk/MoinSupport -Download-url: http://hgweb.boddie.org.uk/MoinSupport/archive/rel-0-4-1.tar.bz2 +Download-url: http://hgweb.boddie.org.uk/MoinSupport/archive/rel-0-4-2.tar.bz2 Summary: Support libraries for MoinMoin extensions License: GPL (version 2 or later) Description: The MoinSupport distribution provides libraries handling datetime diff -r 14b1c0fbe11c -r 0cccc791aac2 README.txt --- a/README.txt Wed Nov 06 12:41:01 2013 +0100 +++ b/README.txt Wed Nov 06 14:40:30 2013 +0100 @@ -64,6 +64,12 @@ If time zone handling is not required, pytz need not be installed. It is, however, highly recommended that pytz be installed. +New in MoinSupport 0.4.2 (Changes since MoinSupport 0.4.1) +---------------------------------------------------------- + + * Moved ItemStore and related functionality into ItemSupport. + * Added support for subpage-based item stores. + New in MoinSupport 0.4.1 (Changes since MoinSupport 0.4) -------------------------------------------------------- diff -r 14b1c0fbe11c -r 0cccc791aac2 setup.py --- a/setup.py Wed Nov 06 12:41:01 2013 +0100 +++ b/setup.py Wed Nov 06 14:40:30 2013 +0100 @@ -8,7 +8,7 @@ author = "Paul Boddie", author_email = "paul@boddie.org.uk", url = "http://hgweb.boddie.org.uk/MoinSupport", - version = "0.4.1", + version = "0.4.2", py_modules = ["ContentTypeSupport", "DateSupport", "GeneralSupport", "ItemSupport", "LocationSupport", "MoinDateSupport", "MoinRemoteSupport", "MoinSupport", "ViewSupport"]