changeset 1039:b521a6667a54 namespaces

access to Item's name through name property instead of meta directly. having a single-item list in update_item won't break tests, so the basic support for list is done. Plus two tests for multiple name indexing, not passing yet Routing is dirtly hacked, but it will be gone soon anyway
author Luis Henrique Fagundes <lhfagundes@gmail.com>
date Mon, 31 Oct 2011 01:42:27 -0200
parents 3f45814eb66e
children 97170e8d69e5
files MoinMoin/_tests/__init__.py MoinMoin/apps/admin/views.py MoinMoin/apps/feed/views.py MoinMoin/apps/frontend/views.py MoinMoin/apps/misc/views.py MoinMoin/items/__init__.py MoinMoin/items/_tests/test_Item.py MoinMoin/script/maint/moinshell.py MoinMoin/storage/middleware/_tests/test_indexing.py MoinMoin/storage/middleware/indexing.py MoinMoin/storage/middleware/protecting.py MoinMoin/storage/middleware/routing.py
diffstat 12 files changed, 104 insertions(+), 30 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/_tests/__init__.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/_tests/__init__.py	Mon Oct 31 01:42:27 2011 -0200
@@ -54,7 +54,7 @@
     item = flaskg.storage[name]
 
     if NAME not in meta:
-        meta[NAME] = name
+        meta[NAME] = [name]
     if CONTENTTYPE not in meta:
         meta[CONTENTTYPE] = u'application/octet-stream'
     rev = item.store_revision(meta, StringIO(data))
--- a/MoinMoin/apps/admin/views.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/apps/admin/views.py	Mon Oct 31 01:42:27 2011 -0200
@@ -226,7 +226,7 @@
     headings = [_('Size'),
                 _('Item name'),
                ]
-    rows = [(rev.meta[SIZE], rev.meta[NAME])
+    rows = [(rev.meta[SIZE], rev.name)
             for rev in flaskg.storage.documents(wikiname=app.cfg.interwikiname)]
     rows = sorted(rows, reverse=True)
     return render_template('admin/itemsize.html',
--- a/MoinMoin/apps/feed/views.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/apps/feed/views.py	Mon Oct 31 01:42:27 2011 -0200
@@ -60,7 +60,7 @@
             query = And([query, Term(NAME_EXACT, item_name), ])
         history = flaskg.storage.search(query, idx_name=ALL_REVS, sortedby=[MTIME], reverse=True, limit=100)
         for rev in history:
-            name = rev.meta[NAME]
+            name = rev.name
             item = rev.item
             this_revid = rev.meta[REVID]
             previous_revid = rev.meta.get(PARENTID)
--- a/MoinMoin/apps/frontend/views.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/apps/frontend/views.py	Mon Oct 31 01:42:27 2011 -0200
@@ -251,7 +251,7 @@
     from MoinMoin.storage.middleware.indexing import convert_to_indexable
     item = flaskg.storage[item_name]
     rev = item[rev]
-    content = convert_to_indexable(rev.meta, rev.data)
+    content = convert_to_indexable(rev.meta, rev.data, item_name)
     return Response(content, 200, mimetype='text/plain')
 
 
@@ -698,7 +698,7 @@
     q = And([Term(WIKINAME, app.cfg.interwikiname),
              Term(USERID, userid)])
     revs = flaskg.storage.search(q, idx_name=ALL_REVS)
-    return [rev.meta[NAME] for rev in revs]
+    return [rev.name for rev in revs]
 
 
 @frontend.route('/+backrefs/<itemname:item_name>')
@@ -729,7 +729,7 @@
     q = And([Term(WIKINAME, app.cfg.interwikiname),
              Or([Term(ITEMTRANSCLUSIONS, item_name), Term(ITEMLINKS, item_name)])])
     revs = flaskg.storage.search(q)
-    return [rev.meta[NAME] for rev in revs]
+    return [rev.name for rev in revs]
 
 
 @frontend.route('/+history/<itemname:item_name>')
@@ -805,7 +805,7 @@
     existing = set()
     revs = flaskg.storage.documents(wikiname=app.cfg.interwikiname)
     for rev in revs:
-        existing.add(rev.meta[NAME])
+        existing.add(rev.name)
         linked.update(rev.meta.get(ITEMLINKS, []))
         transcluded.update(rev.meta.get(ITEMTRANSCLUSIONS, []))
     return existing, linked, transcluded
@@ -1512,7 +1512,7 @@
     :rtype: tuple
     :returns: start word, end word, matches dict
     """
-    item_names = [rev.meta[NAME] for rev in flaskg.storage.documents(wikiname=app.cfg.interwikiname)]
+    item_names = [rev.name for rev in flaskg.storage.documents(wikiname=app.cfg.interwikiname)]
     if item_name in item_names:
         item_names.remove(item_name)
     # Get matches using wiki way, start and end of word
@@ -1682,7 +1682,7 @@
     tags_counts = {}
     for rev in revs:
         tags = rev.meta.get(TAGS, [])
-        logging.debug("name {0!r} rev {1} tags {2!r}".format(rev.meta[NAME], rev.meta[REVID], tags))
+        logging.debug("name {0!r} rev {1} tags {2!r}".format(rev.name, rev.meta[REVID], tags))
         for tag in tags:
             tags_counts[tag] = tags_counts.setdefault(tag, 0) + 1
     tags_counts = sorted(tags_counts.items())
@@ -1716,7 +1716,7 @@
     """
     query = And([Term(WIKINAME, app.cfg.interwikiname), Term(TAGS, tag), ])
     revs = flaskg.storage.search(query, sortedby=NAME_EXACT, limit=None)
-    item_names = [rev.meta[NAME] for rev in revs]
+    item_names = [rev.name for rev in revs]
     return render_template("item_link_list.html",
                            headline=_("Items tagged with %(tag)s", tag=tag),
                            item_name=tag,
--- a/MoinMoin/apps/misc/views.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/apps/misc/views.py	Mon Oct 31 01:42:27 2011 -0200
@@ -30,7 +30,7 @@
 
     sitemap = []
     for rev in flaskg.storage.documents(wikiname=app.cfg.interwikiname):
-        name = rev.meta[NAME]
+        name = rev.name
         mtime = rev.meta[MTIME]
         if False: # was: wikiutil.isSystemItem(name)   XXX add back later, when we have that in the index
             if not SITEMAP_HAS_SYSTEM_ITEMS:
@@ -64,7 +64,7 @@
     See: http://usemod.com/cgi-bin/mb.pl?SisterSitesImplementationGuide
     """
     # XXX we currently also get deleted items, fix this
-    item_names = sorted([rev.meta[NAME] for rev in flaskg.storage.documents(wikiname=app.cfg.interwikiname)])
+    item_names = sorted([rev.name for rev in flaskg.storage.documents(wikiname=app.cfg.interwikiname)])
     content = render_template('misc/urls_names.txt', item_names=item_names)
     return Response(content, mimetype='text/plain')
 
--- a/MoinMoin/items/__init__.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/items/__init__.py	Mon Oct 31 01:42:27 2011 -0200
@@ -198,7 +198,6 @@
         contenttype = rev.meta.get(CONTENTTYPE) or contenttype # use contenttype in case our metadata does not provide CONTENTTYPE
         logging.debug("Item {0!r}, got contenttype {1!r} from revision meta".format(name, contenttype))
         #logging.debug("Item %r, rev meta dict: %r" % (name, dict(rev.meta)))
-
         item = item_registry.get(name, Type(contenttype), rev=rev)
         logging.debug("ItemClass {0!r} handles {1!r}".format(item.__class__, contenttype))
         return item
@@ -524,7 +523,7 @@
         # We only want the sub-item part of the item names, not the whole item objects.
         prefix_len = len(prefix)
         revs = flaskg.storage.search(query, sortedby=NAME_EXACT, limit=None)
-        items = [(rev.meta[NAME], rev.meta[NAME][prefix_len:], rev.meta[CONTENTTYPE])
+        items = [(rev.name, rev.name[prefix_len:], rev.meta[CONTENTTYPE])
                  for rev in revs]
         return items
 
@@ -693,7 +692,7 @@
             terms.append(Term(CONTENTTYPE, contenttype))
         query = And(terms)
         revs = flaskg.storage.search(query, sortedby=NAME_EXACT, limit=None)
-        return [rev.meta[NAME] for rev in revs]
+        return [rev.name for rev in revs]
 
     def do_modify(self, contenttype, template_name):
         # XXX think about and add item template support
--- a/MoinMoin/items/_tests/test_Item.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/items/_tests/test_Item.py	Mon Oct 31 01:42:27 2011 -0200
@@ -13,7 +13,7 @@
 
 from MoinMoin._tests import become_trusted, update_item
 from MoinMoin.items import Item, ApplicationXTar, NonExistent, Binary, Text, Image, TransformableBitmapImage, MarkupItem
-from MoinMoin.config import CONTENTTYPE, ADDRESS, COMMENT, HOSTNAME, USERID, ACTION
+from MoinMoin.config import CONTENTTYPE, ADDRESS, COMMENT, HOSTNAME, USERID, ACTION, NAME
 
 class TestItem(object):
 
@@ -123,6 +123,7 @@
                                   (u'Foo/mn', u'mn', 'image/jpeg', False),
                                   ]
 
+
     def testIndexOnDisconnectedLevels(self):
         # create a toplevel and some sub-items
         basename = u'Bar'
@@ -177,6 +178,27 @@
         expected = {'test_key': 'test_val', CONTENTTYPE: contenttype}
         assert result == expected
 
+    def test_item_can_have_several_names(self):
+        content = u"This is page content"
+
+        update_item(u'Page', 
+                    {NAME: [u'Page', 
+                            u'Another name',
+                            ], 
+                     CONTENTTYPE: u'text/x.moin.wiki'}, content)
+        
+        item1 = Item.create(u'Page')
+        assert item1.name == u'Page'
+        assert item1.meta[CONTENTTYPE] == 'text/x.moin.wiki'
+        assert item1.data == content
+
+        item2 = Item.create(u'Another name')
+        assert item2.name == u'Another name'
+        assert item2.meta[CONTENTTYPE] == 'text/x.moin.wiki'
+        assert item2.data == content
+
+        assert item1.rev.revid == item2.rev.revid
+
     def test_rename(self):
         name = u'Test_Item'
         contenttype = u'text/plain;charset=utf-8'
@@ -203,6 +225,33 @@
         assert item.meta['comment'] == u'renamed'
         assert item.data == u'test_data'
 
+    def test_rename_acts_only_in_active_name_in_case_there_are_several_names(self):
+        content = u"This is page content"
+
+        update_item(u'Page', 
+                    {NAME: [u'Page', 
+                            u'Another name',
+                            ], 
+                     CONTENTTYPE: u'text/x.moin.wiki'}, content)
+        
+        item = Item.create(u'Another name')
+        item.rename(u'New name', comment=u'renamed')
+
+        item1 = Item.create(u'Page')
+        assert item1.name == u'Page'
+        assert item1.meta[CONTENTTYPE] == 'text/x.moin.wiki'
+        assert item1.data == content
+
+        item2 = Item.create(u'New name')
+        assert item2.name == u'New name'
+        assert item2.meta[CONTENTTYPE] == 'text/x.moin.wiki'
+        assert item2.data == content
+
+        assert item1.rev.revid == item2.rev.revid
+
+        item3 = Item.create(u'Another name')
+        assert item3.meta[CONTENTTYPE] == 'application/x-nonexistent'
+
     def test_rename_recursion(self):
         update_item(u'Page', {CONTENTTYPE: u'text/x.moin.wiki'}, u'Page 1')
         update_item(u'Page/Child', {CONTENTTYPE: u'text/x.moin.wiki'}, u'this is child')
--- a/MoinMoin/script/maint/moinshell.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/script/maint/moinshell.py	Mon Oct 31 01:42:27 2011 -0200
@@ -69,11 +69,11 @@
                 sh(global_ns=dict(), local_ns=context)
                 return
             except ImportError:
+                pass
+            except AttributeError:
                 # IPython = 0.11
                 import IPython
                 sh = IPython.embed(banner2=self.banner, user_ns=context)
                 sh()
-            finally:
-                pass
 
         code.interact(self.banner, local=context)
--- a/MoinMoin/storage/middleware/_tests/test_indexing.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/storage/middleware/_tests/test_indexing.py	Mon Oct 31 01:42:27 2011 -0200
@@ -60,7 +60,7 @@
         item = self.imw[item_name]
         assert item # does exist
         rev = item.get_revision(revid)
-        assert rev.meta[NAME] == item_name
+        assert rev.name == item_name
         assert rev.data.read() == data
         revids = [rev.revid for rev in item.iter_revs()]
         assert revids == [revid]
@@ -77,7 +77,7 @@
         # check if the revision was overwritten:
         item = self.imw[item_name]
         rev = item.get_revision(revid)
-        assert rev.meta[NAME] == item_name
+        assert rev.name == item_name
         assert rev.meta[COMMENT] == u'no spam'
         assert rev.data.read() == newdata
         revids = [rev.revid for rev in item.iter_revs()]
@@ -167,7 +167,7 @@
         item = self.imw[item_name]
         rev = item.store_revision(dict(name=item_name), StringIO(data))
         print repr(rev.meta)
-        assert rev.meta[NAME] == item_name
+        assert rev.name == item_name
         assert rev.meta[SIZE] == len(data)
         assert rev.meta[HASH_ALGORITHM] == hashlib.new(HASH_ALGORITHM, data).hexdigest()
         assert ITEMID in rev.meta
@@ -368,7 +368,7 @@
         r = item.store_revision(dict(name=item_name, acl=u'joe:read'), StringIO('public content'))
         revid_public = r.revid
         revids = [rev.revid for rev in self.imw.documents()
-                  if rev.meta[NAME] != u'joe'] # the user profile is a revision in the backend
+                  if rev.name != u'joe'] # the user profile is a revision in the backend
         assert revids == [revid_public]
 
     def test_getitem(self):
--- a/MoinMoin/storage/middleware/indexing.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/storage/middleware/indexing.py	Mon Oct 31 01:42:27 2011 -0200
@@ -56,6 +56,7 @@
 import itertools
 import time
 import datetime
+import types
 from StringIO import StringIO
 
 import logging
@@ -110,7 +111,7 @@
 from MoinMoin.converter import default_registry
 from MoinMoin.util.iri import Iri
 
-def convert_to_indexable(meta, data, is_new=False):
+def convert_to_indexable(meta, data, item_name=None, is_new=False):
     """
     Convert revision data to a indexable content.
 
@@ -140,6 +141,10 @@
         def tell(self, *args, **kw):
             return self.data.tell(*args, **kw)
 
+    if not item_name:
+        # only used for logging, below
+        item_name = unicode(meta[NAME])
+
     rev = PseudoRev(meta, data)
     try:
         # TODO use different converter mode?
@@ -170,7 +175,7 @@
             # transclusions.
             if is_new:
                 # we only can modify new, uncommitted revisions, not stored revs
-                i = Iri(scheme='wiki', authority='', path='/' + meta[NAME])
+                i = Iri(scheme='wiki', authority='', path='/' + item_name)
                 doc.set(moin_page.page_href, unicode(i))
                 refs_conv(doc)
                 # side effect: we update some metadata:
@@ -181,7 +186,7 @@
         # no way
         raise TypeError("No converter for {0} --> {1}".format(input_contenttype, output_contenttype))
     except Exception as e: # catch all exceptions, we don't want to break an indexing run
-        logging.exception("Exception happened in conversion of item {0!r} rev {1} contenttype {2}:".format(meta[NAME], meta.get(REVID, 'new'), meta.get(CONTENTTYPE, '')))
+        logging.exception("Exception happened in conversion of item {0!r} rev {1} contenttype {2}:".format(item_name, meta.get(REVID, 'new'), meta.get(CONTENTTYPE, '')))
         doc = u'ERROR [{0!s}]'.format(e)
         return doc
 
@@ -708,6 +713,7 @@
             # we need to call the method without acl check to avoid endless recursion:
             latest_doc = self.indexer._document(**query) or {}
         self._current = latest_doc
+        self._name = query.get('name_exact')
 
     def _get_itemid(self):
         return self._current.get(ITEMID)
@@ -721,7 +727,15 @@
 
     @property
     def name(self):
-        return self._current.get(NAME, 'DoesNotExist')
+        name = self._current.get(NAME, self._name)
+        if type(name) is types.ListType:
+            if self._name and self._name in name:
+                name = self._name
+            else:
+                name = name[0]
+        elif not name:
+            name = 'DoesNotExist'
+        return name
 
     @classmethod
     def create(cls, indexer, **query):
@@ -779,7 +793,7 @@
             meta[MTIME] = int(time.time())
         #if CONTENTTYPE not in meta:
         #    meta[CONTENTTYPE] = u'application/octet-stream'
-        content = convert_to_indexable(meta, data, is_new=True)
+        content = convert_to_indexable(meta, data, self.name, is_new=True)
         return meta, data, content
 
     def store_revision(self, meta, data, overwrite=False):
@@ -863,7 +877,10 @@
 
     @property
     def name(self):
-        return self.meta.get(NAME, 'DoesNotExist')
+        name = self.meta.get(NAME, 'DoesNotExist')
+        if type(name) is types.ListType:
+            name = name[0]
+        return name
 
     def _load(self):
         meta, data = self.backend.retrieve(self._doc[NAME], self.revid) # raises KeyError if rev does not exist
--- a/MoinMoin/storage/middleware/protecting.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/storage/middleware/protecting.py	Mon Oct 31 01:42:27 2011 -0200
@@ -259,6 +259,10 @@
         return self.rev.revid
 
     @property
+    def name(self):
+        return self.rev.name
+
+    @property
     def meta(self):
         self.require(READ)
         return self.rev.meta
--- a/MoinMoin/storage/middleware/routing.py	Sun Oct 30 22:14:23 2011 -0200
+++ b/MoinMoin/storage/middleware/routing.py	Mon Oct 31 01:42:27 2011 -0200
@@ -99,8 +99,13 @@
                 backend.destroy()
             #XXX else: log info?
 
-    def store(self, meta, data):
-        mountpoint_itemname = meta[NAME]
+    def store(self, meta, data, name = None):
+        if name is None:
+            name = meta[NAME]
+        import types
+        if type(name) is types.ListType:
+            name = name[0]
+        mountpoint_itemname = name
         backend, itemname, mountpoint = self._get_backend(mountpoint_itemname)
         if not isinstance(backend, MutableBackendBase):
             raise TypeError('backend {0!r} mounted at {1!r} is readonly'.format(backend, mountpoint))