[Checkins] SVN: Sandbox/luciano/kirbi/ fixing url generation in several views

Luciano Ramalho luciano at ramalho.org
Wed Aug 15 16:35:31 EDT 2007


Log message for revision 78859:
  fixing url generation in several views
  

Changed:
  U   Sandbox/luciano/kirbi/kirbifetch/src/kirbifetch/fetch.py
  U   Sandbox/luciano/kirbi/src/kirbi/app.py
  U   Sandbox/luciano/kirbi/src/kirbi/book.py
  A   Sandbox/luciano/kirbi/src/kirbi/ftests/learning.txt
  U   Sandbox/luciano/kirbi/src/kirbi/ftests/test_functional.py
  U   Sandbox/luciano/kirbi/src/kirbi/pac.py
  U   Sandbox/luciano/kirbi/src/kirbi/pac_templates/addbooks.pt
  U   Sandbox/luciano/kirbi/src/kirbi/static/master.css
  U   Sandbox/luciano/kirbi/src/kirbi/user.py

-=-
Modified: Sandbox/luciano/kirbi/kirbifetch/src/kirbifetch/fetch.py
===================================================================
--- Sandbox/luciano/kirbi/kirbifetch/src/kirbifetch/fetch.py	2007-08-15 16:23:34 UTC (rev 78858)
+++ Sandbox/luciano/kirbi/kirbifetch/src/kirbifetch/fetch.py	2007-08-15 20:35:30 UTC (rev 78859)
@@ -5,7 +5,9 @@
 from twisted.web import xmlrpc, client
 from os import path
 
-from kirbifetch.amazonsource import AmazonSource
+#XXX this is to run from the buildout
+#from kirbifetch.amazonsource import AmazonSource
+from amazonsource import AmazonSource
 
 from pprint import pprint
 from sys import stdout
@@ -18,17 +20,17 @@
 VERBOSE = False
 
 class Fetch(object):
-    
+
     def __init__(self, xmlrpc_url, poll, callback, source):
         self.pollServer = xmlrpc.Proxy(xmlrpc_url)
         self.pollMethod = poll
         self.callback = callback
         self.source = source
-        
+
     def poll(self):
         deferred = self.pollServer.callRemote(self.pollMethod)
         deferred.addCallback(self.polled).addErrback(self.pollError)
-    
+
     def polled(self, isbns):
         i = 0
         if isbns:
@@ -42,18 +44,18 @@
             stdout.write('.')
             stdout.flush()
         reactor.callLater(i+POLL_INTERVAL, self.poll)
-            
+
     def pollError(self, error):
         print 'Error in deferred poll call:', error
         # if there was an error, wait a bit longer to try again
         reactor.callLater(POLL_INTERVAL*4, self.poll)
-            
+
     def downloadItemsPage(self, isbns):
         url = self.source.buildMultipleBookDetailsURL(isbns)
         deferred = client.getPage(url)
         deferred.addCallback(self.downloadedItemsPage, isbns)
         deferred.addErrback(self.downloadError, url)
-          
+
     def downloadedItemsPage(self, xml, isbns):
         book_list = self.source.parseMultipleBookDetails(xml)
         deferred = self.pollServer.callRemote(self.callback, book_list)
@@ -68,20 +70,20 @@
                 filepath = path.join(filepath,'src','kirbi','static',
                                     'covers','large',filename)
                 # avoid duplicate downloads
-                if not path.exists(filepath): 
+                if not path.exists(filepath):
                     deferred = client.getPage(url)
                     deferred.addCallback(self.downloadedImage, filepath)
                     deferred.addErrback(self.downloadError, url)
                 else:
                     print 'skipping existing:', filepath
-                
+
         if KEEP_FILES:
             filename = '_'.join(isbns)+'.xml'
             out = file(path.join(self.source.name,filename), 'w')
             out.write(xml.replace('><','>\n<'))
             out.close()
 
-    
+
     def downloadedImage(self, bytes, filepath):
         print 'saving:', filepath
         out = file(filepath, 'wb')

Modified: Sandbox/luciano/kirbi/src/kirbi/app.py
===================================================================
--- Sandbox/luciano/kirbi/src/kirbi/app.py	2007-08-15 16:23:34 UTC (rev 78858)
+++ Sandbox/luciano/kirbi/src/kirbi/app.py	2007-08-15 20:35:30 UTC (rev 78859)
@@ -10,21 +10,30 @@
 PAC_NAME = u'pac'
 USER_FOLDER_NAME = u'u'
 
+def getApplication(context):
+    obj = context
+    while obj is not None:
+        if isinstance(obj, grok.Application):
+            return obj
+        obj = obj.__parent__
+    raise ValueError("No application found.")
+
+
 class Kirbi(grok.Application, grok.Container):
     """Peer-to-peer library system."""
     def __init__(self):
         global sitePac, siteUsers, siteUsersURL
         super(Kirbi, self).__init__()
-        self[PAC_NAME] = Pac()
-        self[USER_FOLDER_NAME] = UserFolder()
+        self.pac = self[PAC_NAME] = Pac()
+        self.user_folder = self[USER_FOLDER_NAME] = UserFolder()
 
 class Index(grok.View):
 
     def pac_url(self):
-        return self.url(self.context[PAC_NAME])
+        return self.url(self.context.pac)
 
     def login_url(self):
-        return self.url(self.context[USER_FOLDER_NAME],'login')
+        return self.url(self.context.user_folder,'login')
 
 class BookIndexes(grok.Indexes):
     grok.site(Kirbi)
@@ -33,12 +42,11 @@
     title = index.Text()
     isbn13 = index.Field()
     searchableText = index.Text()
-    
+
     #XXX: check whether this is working:
     # the creatorSet book method was not being called
     creatorsSet = index.Set()
-    
+
 class Master(grok.View):
     """The master page template macro."""
     grok.context(Interface)
-            

Modified: Sandbox/luciano/kirbi/src/kirbi/book.py
===================================================================
--- Sandbox/luciano/kirbi/src/kirbi/book.py	2007-08-15 16:23:34 UTC (rev 78858)
+++ Sandbox/luciano/kirbi/src/kirbi/book.py	2007-08-15 20:35:30 UTC (rev 78859)
@@ -5,8 +5,6 @@
 from isbn import isValidISBN, isValidISBN10, isValidISBN13, filterDigits
 from isbn import convertISBN10toISBN13, convertISBN13toLang
 
-USER_FOLDER_NAME = u'u'
-
 import os
 
 STATIC_PATH = os.path.join(os.path.dirname(__file__), 'static')
@@ -237,7 +235,7 @@
 
     def searchableText(self):
         return self.title + ' ' + ' '.join(self.creators)
-    
+
     def update(self, **kwargs):
         for key, value in kwargs.items():
             setattr(self,key,value)
@@ -251,7 +249,7 @@
     pass
 
 class Index(grok.View):
-    
+
     def __init__(self, *args):
         # XXX: Is this super call really needed for a View sub-class?
         super(Index,self).__init__(*args)
@@ -274,4 +272,3 @@
         cover_name = 'covers/large/'+self.context.__name__+'.jpg'
         return self.static.get(cover_name,
                                self.static['covers/small-placeholder.jpg'])()
-

Added: Sandbox/luciano/kirbi/src/kirbi/ftests/learning.txt
===================================================================
--- Sandbox/luciano/kirbi/src/kirbi/ftests/learning.txt	                        (rev 0)
+++ Sandbox/luciano/kirbi/src/kirbi/ftests/learning.txt	2007-08-15 20:35:30 UTC (rev 78859)
@@ -0,0 +1,36 @@
+====================================
+Tests for learning Grok and Zope 3
+====================================
+
+These are random tests that I am using to learn about Grok and Zope 3 (LR).
+
+First we setup the app::
+
+    >>> from grok.ftests.xmlrpc_helper import ServerProxy
+    >>> from kirbi.app import Kirbi
+    >>> root = getRootFolder()
+    >>> kirbi = root['kirbi'] = Kirbi()
+
+A Pac instance is created when Kirbi is initialized::
+
+    >>> pac = kirbi['pac']
+    >>> pac
+    <kirbi.pac.Pac object at ...>
+
+No matter how deep you are, you can always get to the root app::
+
+    >>> import grok
+    >>> obj = pac
+    >>> while obj is not None:
+    ...     if isinstance(obj, grok.Application):
+    ...         break
+    ...     obj = obj.__parent__
+    >>> obj
+    <kirbi.app.Kirbi object at ...>
+
+There is a shortcut for this in the Grok API, but for some reason it doesn't
+work in this test:
+
+    >>> theApp = grok.getSite()
+    >>> repr(theApp)
+    'None'

Modified: Sandbox/luciano/kirbi/src/kirbi/ftests/test_functional.py
===================================================================
--- Sandbox/luciano/kirbi/src/kirbi/ftests/test_functional.py	2007-08-15 16:23:34 UTC (rev 78858)
+++ Sandbox/luciano/kirbi/src/kirbi/ftests/test_functional.py	2007-08-15 20:35:30 UTC (rev 78859)
@@ -20,11 +20,11 @@
 
 def test_suite():
     suite = unittest.TestSuite()
-    docfiles = ['xmlrpc.txt', 'user.txt']
+    docfiles = ['xmlrpc.txt', 'user.txt', 'learning.txt']
 
     for docfile in docfiles:
         test = FunctionalDocFileSuite(
-                    docfile, 
+                    docfile,
                     setUp=setUp, tearDown=tearDown,
                     globs=dict(http=HTTPCaller(),
                         getRootFolder=getRootFolder,

Modified: Sandbox/luciano/kirbi/src/kirbi/pac.py
===================================================================
--- Sandbox/luciano/kirbi/src/kirbi/pac.py	2007-08-15 16:23:34 UTC (rev 78858)
+++ Sandbox/luciano/kirbi/src/kirbi/pac.py	2007-08-15 20:35:30 UTC (rev 78859)
@@ -14,15 +14,13 @@
 from persistent.dict import PersistentDict
 from time import localtime, strftime
 
-USER_FOLDER_NAME = u'u'
-
 class Pac(grok.Container):
     """Pac (public access catalog)
 
     Bibliographic records for all items (books, disks etc.) known to this
     Kirbi instance. The contents of this catalog is public, but information
     about item ownership and availability is not kept here.
-    
+
     In library science the term "catalog" is used to refer to
     "a comprehensive list of the materials in a given collection".
     The Pac name was chosen to avoid confusion with zc.catalog.
@@ -54,16 +52,16 @@
     def dumpIncomplete(self):
         dump = list(self.incomplete_isbns)
         self.pending_isbns.update(self.incomplete_isbns)
-        self.incomplete_isbns.clear()        
+        self.incomplete_isbns.clear()
         return dump
-    
+
     def retryPending(self, isbns):
         for isbn13 in isbns:
             if isbn13 in self.pending_isbns:
                 self.incomplete_isbns[isbn13] = self.pending_isbns[isbn13]
                 del self.pending_isbns[isbn13]
 
-    def updateBooks(self, book_dict_list):                
+    def updateBooks(self, book_dict_list):
         updated = 0
         for book_dict in book_dict_list:
             isbn13 = book_dict.get('isbn13')
@@ -78,16 +76,16 @@
                 modified(book, changed)
                 updated += 1
         return updated
-            
+
 @grok.subscribe(Book, grok.IObjectAddedEvent)
 def bookAdded(book, event):
     if not book.title and book.isbn13:
         pac = book.__parent__
         pac.addIncomplete(book.isbn13)
-        
+
 class Index(grok.View):
     grok.context(Pac)
-            
+
     def coverUrl(self, book):
         cover_name = 'covers/large/'+book.isbn13+'.jpg'
         return self.static.get(cover_name,
@@ -151,12 +149,12 @@
         self.applyData(book, **data)
         self.context.addBook(book)
         self.redirect(self.url(self.context))
-        
+
 class AddBooks(grok.View):
     grok.context(Pac)
-    
+
     invalid_isbns = []
-    
+
     def update(self, isbns=None, retry_isbns=None):
         self.invalid_isbns = []
         if isbns is not None:
@@ -175,7 +173,7 @@
                                          or self.context.getPending()):
             self.request.response.setHeader("Refresh", "5; url=%s" % self.url())
 
-                    
+
     def invalidISBNs(self):
         if self.invalid_isbns:
             return '\n'.join(self.invalid_isbns)
@@ -187,25 +185,25 @@
                     isbn_dict.items())
         return (dict(timestamp=timestamp,isbn=isbn)
                 for timestamp, isbn in sorted(pairs))
-            
+
     def incompleteIsbns(self):
         return list(self.sortedByTime(self.context.getIncomplete()))
 
     def pendingIsbns(self):
         return list(self.sortedByTime(self.context.getPending()))
-    
+
 class NameChooser(grok.Adapter, BaseNameChooser):
     implements(INameChooser)
 
     def nextId(self,fmt='%s'):
         """Binary search to quickly find an unused numbered key.
-        
+
         This was designed to scale well when importing large batches of books
         without ISBN, while keeping the ids short.
-        
+
         The algorithm generates a key right after the largest numbered key or
         in some unused lower numbered slot found by the second loop.
-        
+
         If keys are later deleted in random order, some of the resulting slots
         will be reused and some will not.
         """

Modified: Sandbox/luciano/kirbi/src/kirbi/pac_templates/addbooks.pt
===================================================================
--- Sandbox/luciano/kirbi/src/kirbi/pac_templates/addbooks.pt	2007-08-15 16:23:34 UTC (rev 78858)
+++ Sandbox/luciano/kirbi/src/kirbi/pac_templates/addbooks.pt	2007-08-15 20:35:30 UTC (rev 78859)
@@ -17,18 +17,18 @@
   <table><tr>
     <td valign="top">
     <form tal:attributes="action view/url" method="post">
-        <p>Type or scan several ISBNs separated by spaces or newlines.</p>
-        <p>Either 10 or 13-digit ISBNs can be used.</p>
+        <p>Type or scan several ISBNs separated by spaces or newlines.<br />
+           Either 10 or 13-digit ISBNs can be used.</p>
+        <p class="error" tal:condition="view/invalidISBNs">
+            The numbers remaining in the field below are not valid ISBN-10
+            or ISBN-13.
+        </p>
         <textarea name="isbns" rows="20" cols="40"
             tal:content="view/invalidISBNs">
         </textarea>
-        <br /> 
+        <br />
         <input type="submit" value="Add books">
         <br />
-        <p tal:condition="view/invalidISBNs">
-            The numbers remaining in the field above are not valid ISBN-10
-            or ISBN-13.
-        </p>
     </form>
     <hr />
     <p>
@@ -47,14 +47,14 @@
                 <th align="right" tal:content="repeat/item/number" />
                 <td tal:content="item/timestamp" />
                 <td>
-                    <a tal:attributes="href python:view.url(item['isbn'])+'/details'"
+                    <a tal:attributes="href python:view.url(item['isbn'])"
                             tal:content="item/isbn">9780123456789</a>
-    
+
                 </td>
             </tr>
         </table>
     </div>
-        
+
     <form tal:condition="view/pendingIsbns" method="post"
         tal:attributes="action view/url">
         <h3>Pending Book Searches</h3>
@@ -93,14 +93,14 @@
                 <td>
                     <input type="checkbox" name="retry_isbns:list"
                             tal:attributes="value item/isbn" />
-    
+
                 </td>
                 <th align="right" tal:content="repeat/item/number" />
                 <td tal:content="item/timestamp" />
                 <td>
-                    <a tal:attributes="href python:view.url(item['isbn'])+'/details'"
+                    <a tal:attributes="href python:view.url(item['isbn'])"
                             tal:content="item/isbn">9780123456789</a>
-    
+
                 </td>
                 <td>
                     <a tal:attributes="href string:http://www.worldcatlibraries.org/search?q=${item/isbn}"

Modified: Sandbox/luciano/kirbi/src/kirbi/static/master.css
===================================================================
--- Sandbox/luciano/kirbi/src/kirbi/static/master.css	2007-08-15 16:23:34 UTC (rev 78858)
+++ Sandbox/luciano/kirbi/src/kirbi/static/master.css	2007-08-15 20:35:30 UTC (rev 78859)
@@ -120,3 +120,7 @@
 .unknown {
     color: gray;
 }
+
+.error {
+    color: red;
+}

Modified: Sandbox/luciano/kirbi/src/kirbi/user.py
===================================================================
--- Sandbox/luciano/kirbi/src/kirbi/user.py	2007-08-15 16:23:34 UTC (rev 78858)
+++ Sandbox/luciano/kirbi/src/kirbi/user.py	2007-08-15 20:35:30 UTC (rev 78859)
@@ -8,13 +8,13 @@
 
 class UserFolder(grok.Container):
     pass
-    
+
 class User(grok.Container):
     """A Kirbi user implementation.
-    
+
     A User will contain Copy instances, representing book copies
     owned by the user.
-    
+
         >>> alice = User('alice', u'Alice Cooper', u'headless-chicken')
         >>> IUser.providedBy(alice)
         True
@@ -25,11 +25,11 @@
     """
 
     implements(IUser)
-    
+
     login = u''
     name = u''
     password = u''
-        
+
     def __init__(self, login, name, password):
         super(User, self).__init__()
         self.login = login
@@ -38,13 +38,13 @@
 
     def passwordHash(self):
         return sha.new(self.password).hexdigest()
-    
+
     def name_and_login(self):
         if self.name:
             return '%s (%s)' % (self.name, self.login)
         else:
             return self.login
-        
+
 class Index(grok.View):
     grok.context(User)
 
@@ -74,7 +74,7 @@
     @property
     def description(self):
         return self.context.name_and_login()
-    
+
 class UserSearch(grok.View):
     grok.context(UserFolder)
     grok.name('index')
@@ -86,7 +86,7 @@
     grok.context(UserFolder)
     def render(self):
         return 'This should log you in...'
-    
+
 class Logout(grok.View):
     grok.context(UserFolder)
     def render(self):
@@ -95,7 +95,7 @@
 class Join(grok.AddForm):
     grok.context(UserFolder)
     """User registration form"""
-    
+
     form_fields = grok.AutoFields(IUser)
 
     @grok.action('Add entry')
@@ -103,8 +103,8 @@
         login = data['login']
         self.context[login] = User(**data)
         self.redirect(self.url(login))
-        
-        
+
+
 class UserAuthenticationPlugin(object):
     """Simple authentication and search plugin"""
     implements(IAuthenticatorPlugin)
@@ -114,8 +114,8 @@
         {'id':'bob', 'login':'bob', 'password':'123'}
         )
 
-    prefix = "users" # principal id prefix
-    
+    prefix = "" # principal id prefix
+
     def principalInfo(self, id):
         """Find a principal given an id"""
         for principal in self.principals:
@@ -129,5 +129,3 @@
                credentials['password']==principal['password']:
                 return (self.prefix + "." + principal['id'],
                          {'login' : principal['login']})
-
-



More information about the Checkins mailing list