Commits

Christian Theune committed f316fd8

Clean up. Flake8 and some refactoring.

Comments (0)

Files changed (142)

src/asm/archive/skin.py

 # -*- coding: utf-8 -*-
-
 from asm.cms.interfaces import IDataUri
 from asm.mediagallery.interfaces import IMediaGallery
 from asm.mediagallery.interfaces import IMediaGalleryAdditionalInfo
 from zope.app.form.browser.textwidgets import TextWidget
 import asm.cms
 import asm.cmsui.interfaces
+import asm.cmsui.public.layout
 import asm.cmsui.retail
 import asm.mediagallery.externalasset
 import asm.mediagallery.gallery
     grok.context(asm.cms.interfaces.IEdition)
 
 
-class LayoutHelper(grok.View):
-    grok.context(zope.interface.Interface)
+class LayoutHelper(asm.cmsui.public.layout.LayoutHelper):
     grok.layer(ISkin)
 
-    # A helper class to get access to the static directory in this module from
-    # the layout.
-
-    def render(self):
-        return ''
 
 DEFAULT_YEARS = 10
 YEAR_MATCH = re.compile("^\d{4}$")

src/asm/archive/testing.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import os.path
 import zope.app.testing.functional
 

src/asm/assemblytv/skin.py

 # -*- coding: utf-8 -*-
-# Copyright (c) 2012 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms
 import asm.cmsui.interfaces
+import asm.cmsui.public.layout
 import asm.cmsui.retail
 import asm.mediagallery.externalasset
 import asm.mediagallery.gallery
     grok.context(asm.cms.interfaces.IEdition)
 
 
-class LayoutHelper(grok.View):
-    grok.context(zope.interface.Interface)
+class LayoutHelper(asm.cmsui.public.layout.LayoutHelper):
     grok.layer(ISkin)
 
-    def current_language(self):
-        cookie_lang = self.request.cookies.get('asm.translation.lang')
-        if cookie_lang in asm.translation.translation.current():
-            return cookie_lang
-        return asm.translation.translation.fallback()
-
     @property
     def navigation(self):
         if 'navigation' in self.application:
         else:
             return None
 
-    # A helper class to get access to the static directory in this module from
-    # the layout.
-
-    def render(self):
-        return ''
-
 
 class Homepage(asm.cmsui.retail.Pagelet):
 

src/asm/assemblytv/testing.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import os.path
 import zope.app.testing.functional
 

src/asm/banner/banner.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.banner.interfaces
 import asm.cms.interfaces
 import asm.cms.edition

src/asm/banner/testing.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import os.path
 import zope.app.testing.functional
 

src/asm/cacheviews/cacheviews.py

 import zope.component
 import zope.interface
 
+
 class Cache(grok.View):
     grok.context(zope.interface.Interface)
 
     default_cache_time = datetime.timedelta(weeks=2)
 
     def update(self, cache_seconds=None):
-        utcnow = datetime.datetime(2009,1,1).utcnow()
+        utcnow = datetime.datetime(2009, 1, 1).utcnow()
         cache_time = self.default_cache_time
         if cache_seconds is not None:
             seconds = int(cache_seconds)
             "Expires",
             asm.cms.utils.datetime_to_http_timestamp(expiresAt)
             )
+        max_age = cache_time.seconds + cache_time.days * 86400
         self.request.response.setHeader(
             "Cache-Control",
-            "max-age=%d,public" % (cache_time.seconds + cache_time.days * 86400)
-            )
+            "max-age=%d,public" % max_age)
         self.request.response.setHeader(
-            'Vary',
-            "Accept-Encoding,Accept-Language,Cookie,Authorization"
-            )
+            'Vary', 'Accept-Encoding,Accept-Language,Cookie,Authorization')
 
     def render(self):
         # XXX this should work for any view and not just assume index view.

src/asm/cacheviews/testing.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import os.path
 import zope.app.testing.functional
 

src/asm/cms/__init__.py

-import asm.cms.utils
-import grok
-import urlparse
-import zope.publisher.http
-import zope.component
+from .patches import apply_patches
 
-
-def get_application(context):
-    obj = context
-    while obj is not None:
-        if isinstance(obj, grok.Application):
-            return obj
-        obj = obj.__parent__
-    raise ValueError("No application found.")
-
-def get_application_for_view(self):
-    return get_application(self.context)
-
-grok.View.application = property(fget=get_application_for_view)
-
-
-def cms_edition(self):
-    return asm.cms.edition.select_edition(self.application, self.request)
-
-grok.View.cms_edition = property(fget=cms_edition)
-
-def view(self, name):
-    return zope.component.getMultiAdapter(
-        (self.context, self.request), name=name)
-grok.View.view = view
-
-def resolve_relative_urls(self, content, source):
-
-    def resolve(url):
-        for prefix in ['http:', 'ftp:', 'https:', 'mailto:', 'irc:', '/', '?',
-                       '#']:
-            if url.startswith(prefix):
-                return
-        return urlparse.urljoin(base, url)
-
-    # Always turn the source into a folder-like path element to avoid that
-    # pointing to '.' will resolve in the parent's index.
-    base = self.url(source) + '/'
-    return asm.cms.utils.rewrite_urls(content, resolve)
-
-grok.View.resolve_relative_urls = resolve_relative_urls
-
-# XXX Monkey patch to force requests include Accept Encoding in the Vary header.
-old_setHeader = zope.publisher.http.HTTPResponse.setHeader
-def force_vary_header(self, name, value, *args, **kw):
-    if name.lower() == 'vary' and 'accept-encoding' not in value.lower():
-        value += ",Accept-Encoding"
-    result = old_setHeader(self, name, value, *args, **kw)
-    return result
-zope.publisher.http.HTTPResponse.setHeader = force_vary_header
-
+apply_patches()
 
 # Provide re-exports of public API
 

src/asm/cms/asset.py

-# Copyright (c) 2009-2010 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.interfaces
 import base64
 # This is also the amount that magic library uses for file type detection.
 MAGIC_FILE_BYTES = 8192
 
+
 class Asset(asm.cms.edition.Edition):
     """An asset stores binary data, like images.
 
             return None
         if self._content_type is not None:
             return self._content_type
-        self._content_type = magic.whatis(self.content.open('r').read(MAGIC_FILE_BYTES))
+        significant_bytes = self.content.open('r').read(MAGIC_FILE_BYTES)
+        self._content_type = magic.whatis(significant_bytes)
         return self._content_type
 
 

src/asm/cms/cms.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import z3c.baseregistry.baseregistry
 import asm.cms.page
 import grok

src/asm/cms/edition.py

-# Copyright (c) 2010-2011 Assembly Organizing
-# See also LICENSE.txt
-
 import BTrees.OOBTree
 import asm.cms.interfaces
 import datetime
     return EditionParameters(parameters)
 
 
-
 @grok.subscribe(asm.cms.interfaces.IEdition, grok.IObjectModifiedEvent)
 def annotate_modification_date(obj, event):
     obj.modified = datetime.datetime.now(pytz.UTC)
     return scores[0][0]
 
 
-def find_editions(root, request=None, schema=zope.interface.Interface, recurse=True):
+def find_editions(root, request=None, schema=zope.interface.Interface,
+                  recurse=True):
     for page in root.subpages:
         if request is not None:
             editions = [select_edition(page, request)]

src/asm/cms/generations/evolve1.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
-from zope.app.zopeappgenerations import getRootFolder
-import asm.cms.cms
-
-
 def evolve(context):
     pass

src/asm/cms/generations/evolve2.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 from zope.app.zopeappgenerations import getRootFolder
 import asm.cms.cms
 import pytz

src/asm/cms/generations/evolve3.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 from zope.app.zopeappgenerations import getRootFolder
 import asm.cms.cms
 import zope.app.component.hooks

src/asm/cms/generations/evolve4.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 from zope.app.zopeappgenerations import getRootFolder
 import ZODB.blob
 import asm.cms.cms

src/asm/cms/generations/evolve5.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 from zope.app.zopeappgenerations import getRootFolder
-import ZODB.blob
 import asm.cms.cms
 import zope.app.component.hooks
 import zope.intid.interfaces

src/asm/cms/generations/evolve6.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
+from asm.mediagallery.interfaces import IMediaGalleryAdditionalInfo
 from zope.app.zopeappgenerations import getRootFolder
-import ZODB.blob
 import asm.cms.cms
 import zope.app.component.hooks
 import zope.intid.interfaces
                 if not obj.type == 'externalasset':
                     continue
                 for edition in obj.editions:
-                    gallery = asm.mediagallery.interfaces.IMediaGalleryAdditionalInfo(edition)
+                    gallery = IMediaGalleryAdditionalInfo(edition)
                     gallery.thumbnail = edition.thumbnail
                     edition.thumbnail = None
         finally:

src/asm/cms/generations/evolve7.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
-
 from zope.app.zopeappgenerations import getRootFolder
-import ZODB.blob
 import asm.cms.cms
 import zope.app.component.hooks
 import zope.intid.interfaces

src/asm/cms/generations/evolve8.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
-
 from zope.app.zopeappgenerations import getRootFolder
-import ZODB.blob
 import asm.cms.cms
 import zope.app.component.hooks
 import zope.intid.interfaces

src/asm/cms/generations/evolve9.py

-# Copyright (c) 2012 gocept gmbh & co. kg
-# See also LICENSE.txt
-
-
 from zope.app.zopeappgenerations import getRootFolder
 import asm.cms.cms
 import asm.cms.interfaces

src/asm/cms/homepage.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms
 import asm.cms.edition
 import zope.interface

src/asm/cms/htmlpage.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.interfaces
 import asm.cms.utils

src/asm/cms/importer.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import ZODB.blob
 import asm.cms
 import asm.cms.cms
 import zope.schema
 import zope.traversing.api
 
+
 def base64_to_blob(data):
     value = ZODB.blob.Blob()
     f = value.open('w')
     f.close()
     return value
 
+
 class ImportError(ValueError):
     pass
 
                 except KeyError:
                     # Leave existing content alone.
                     if not allow_duplicates:
-                        errors.append(
-                            "Duplicate page '%s' with edition '%s' detected" % (
-                                page_path, parameters_value))
+                        errors.append('Duplicate page "%s" '
+                                      'with edition "%s" detected' % (
+                                      page_path, parameters_value))
                     continue
                 getattr(self, 'import_%s' % page.type)(edition, edition_node)
                 edition.title = edition_node.get('title')

src/asm/cms/interfaces.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import ZODB.blob
 import zc.sourcefactory.basic
 import zope.component
     """
 
     def __call__(page):
-        """Return a set of parameters to be used for the initial edition of this page."""
+        """Return a set of parameters to be used for the initial edition."""
 
 
 class IHTMLPage(zope.interface.Interface):
         title=u'Profile',
         source=ProfileSource())
 
+
 class ISearchSites(zope.interface.Interface):
 
     sites = zope.schema.List(
 
 
 class IRedirect(zope.interface.Interface):
+
     target_url = zope.schema.URI(title=u'Redirect URI')
 
 
 class IDataUri(zope.interface.Interface):
+
     datauri = zope.schema.URI(title=u'Data URI')
-

src/asm/cms/news.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms
 import asm.cms.interfaces
 import asm.cms.edition
                     u'Please note that depending on the context the image '
                     u'may be displayed in different styles.')
 
+
 class TeaserAnnotation(grok.Annotation):
     grok.implements(INewsFields)
     grok.provides(INewsFields)

src/asm/cms/page.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.interfaces
+import asm.cms.patches
 import asm.cms.utils
 import grok
 import zope.app.form.browser.source
         elif type in ['before', 'after']:
             # Insert new object before this object, or after this object.
             target = self.__parent__
-            if asm.cms.get_application(self) == self:
+            if asm.cms.patches.get_application(self) == self:
                 raise ValueError("Can not move outside this application")
             keys = list(target)
             target_position = keys.index(self.__name__)

src/asm/cms/patches.py

+import asm.cms.utils
+import grok
+import urlparse
+import zope.component
+import zope.publisher.http
+
+
+def get_application(context):
+    obj = context
+    while obj is not None:
+        if isinstance(obj, grok.Application):
+            return obj
+        obj = obj.__parent__
+    raise ValueError("No application found.")
+
+
+def get_application_for_view(self):
+    return get_application(self.context)
+
+
+def cms_edition(self):
+    return asm.cms.edition.select_edition(self.application, self.request)
+
+
+def view(self, name):
+    return zope.component.getMultiAdapter(
+        (self.context, self.request), name=name)
+
+
+def resolve_relative_urls(self, content, source):
+
+    def resolve(url):
+        for prefix in ['http:', 'ftp:', 'https:', 'mailto:', 'irc:', '/', '?',
+                       '#']:
+            if url.startswith(prefix):
+                return
+        return urlparse.urljoin(base, url)
+
+    # Always turn the source into a folder-like path element to avoid that
+    # pointing to '.' will resolve in the parent's index.
+    base = self.url(source) + '/'
+    return asm.cms.utils.rewrite_urls(content, resolve)
+
+
+# XXX Monkey patch to force requests to include the 'Accept-Encoding'
+# in the Vary header.
+def force_vary_header(self, name, value, *args, **kw):
+    if name.lower() == 'vary' and 'accept-encoding' not in value.lower():
+        value += ",Accept-Encoding"
+    result = old_setHeader(self, name, value, *args, **kw)
+    return result
+
+old_setHeader = zope.publisher.http.HTTPResponse.setHeader
+
+
+def apply_patches():
+    grok.View.application = property(fget=get_application_for_view)
+    grok.View.cms_edition = property(fget=cms_edition)
+    grok.View.resolve_relative_urls = resolve_relative_urls
+    grok.View.view = view
+    zope.publisher.http.HTTPResponse.setHeader = force_vary_header

src/asm/cms/redirect.py

-# Copyright (c) 2011 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.interfaces
 import zope.interface
 import zope.publisher.interfaces.browser
 import zope.traversing.browser.interfaces
 
+
 class Redirect(asm.cms.edition.Edition):
 
     zope.interface.implements(asm.cms.interfaces.IRedirect)

src/asm/cms/replace.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms
 import asm.cms.cms
 import asm.cms.interfaces
         content_hash = hashlib.sha1().hexdigest()[:10]
         self.id = '%s-%s-%s-%s' % (self.page_id, content_hash, self.offset,
                                    urllib.quote(self.term.encode('base64')))
-
-

src/asm/cms/scripts/copysite.py

-# Copyright (c) 2010-2011 Assembly Organizing
-# See also LICENSE.txt
-
 import argparse
 import asm.cms.cms
-import sys
 import transaction
 import zope.app.component.hooks
 import zope.copypastemove.interfaces
 
 args = parser.parse_args()
 
-old_site = root[args.old]
-new_site = root[args.new] = asm.cms.cms.CMS()
+old_site = root[args.old] # NOQA
+new_site = root[args.new] = asm.cms.cms.CMS() # NOQA
 
 transaction.savepoint()
 zope.app.component.hooks.setSite(new_site)

src/asm/cms/search.py

-# Copyright (c) 2009-2011 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.cms
 import asm.cms.interfaces
 import grok

src/asm/cms/testing.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.cms
 import os.path
 import transaction

src/asm/cms/tests/test_asset.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
+import ZODB.blob
 import asm.cms.asset
 import os.path
 import unittest
-import ZODB.blob
 
 
 class AssetTests(unittest.TestCase):

src/asm/cms/tests/test_edition.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.edition
 import minimock
 import unittest
 
 EP = asm.cms.edition.EditionParameters
 
+
 class DummyRequest(dict):
     zope.interface.implements(zope.annotation.interfaces.IAnnotations)
 
         self.assertEquals(p1, p1_1)
 
     def test_parameters_iter(self):
-        p = EP([1,2,3])
-        self.assertEquals(set([1,2,3]), set(p))
+        p = EP([1, 2, 3])
+        self.assertEquals(set([1, 2, 3]), set(p))
 
     def test_parameters_replace_simple(self):
         self.assertEquals(
     def test_select_2_editions_with_same_content_selected_by_identity(self):
         # We once hit a bad issue where we used a comparison in
         # `select_edition` that was based on identity. However, due to the
-        # fact that we have a special implementation of __eq__ we need to 
+        # fact that we have a special implementation of __eq__ we need to
         # ensure that we select based on identity rather than equality.
         # This test isn't bullet proof, but it keeps us from making the
         # exactly same mistake again.

src/asm/cms/tests/test_htmlpage.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import unittest
-
 import asm.cms.htmlpage
 
 

src/asm/cms/tests/test_import.py

-# Copyright (c) 2009-2011 Assembly Organizing
-# See also LICENSE.txt
-
 from asm.cms.htmlpage import fix_relative_links
 import asm.cms.importer
 import asm.cms.testing

src/asm/cms/tests/test_page.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.page
 import transaction
-import unittest
-import zope.app.component.hooks
-import zope.intid.interfaces
-import zope.component
 
 
 class PageTests(asm.cms.testing.FunctionalTestCase):

src/asm/cms/tests/test_replace.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.cms
 import asm.cms.htmlpage
 import asm.cms.replace
 import asm.cms.testing
-import transaction
-import unittest
 
 
 class TestReplace(asm.cms.testing.FunctionalTestCase):

src/asm/cms/tests/test_typography.py

-import asm.cms.cms
-import asm.cms.testing
-import asm.cms.typography
-import grok
-import unittest
-
-
-class ParagraphTests(unittest.TestCase):
-
-    def setUp(self):
-        self.page = asm.cms.htmlpage.HTMLPage()
-
-    def clean(self):
-        asm.cms.typography.clean_typography(self.page)
-        return self.page.content
-
-    def test_remove_empty_paragraph(self):
-        self.page.content = '<p></p>'
-        self.assertEquals('', self.clean())
-
-    def test_only_remove_empty_paragraph(self):
-        self.page.content = '<p></p><p>Assembly 2010</p><p></p>'
-        self.assertEquals('<p>Assembly 2010</p>', self.clean())
-
-    def test_remove_whitespace_paragraph(self):
-        self.page.content = '<p>          </p>'
-        self.assertEquals('', self.clean())
-
-    def test_remove_newline(self):
-        self.page.content = '<p>\n</p>'
-        self.assertEquals('', self.clean())
-
-    def test_no_removal_of_whitespace_tags(self):
-        self.page.content = '<br/>'
-        self.assertEquals('<br/>', self.clean())
-
-    def test_title_in_content(self):
-        self.page.title = 'Assembly 2010'
-        self.page.content = '<H1>Assembly 2010</H1><p>Assembly on paras</p>'
-        self.assertEquals('<p>Assembly on paras</p>', self.clean())
-
-    def test_title_no_content(self):
-        self.page.title = 'Assembly 2010'
-        self.page.content = '<H1></H1><p>Assembly on paras</p>'
-        self.assertEquals('<p>Assembly on paras</p>', self.clean())
-
-    def test_not_removing_parent(self):
-        # Our output gets beautified so we end up with additional whitespace.
-        self.page.content = '<p><img src="test" /></p>'
-        self.assertEquals('<p>\n    <img src="test"/>\n  </p>', self.clean())

src/asm/cms/tests/test_utils.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
-import asm.cms.cms
+from asm.cms.patches import get_application_for_view
 import asm.cms.testing
 import asm.cms.utils
 import datetime
         self.assertEquals('asdf-bsdf',
                           asm.cms.utils.normalize_name(u'asdf\xfcbsdf'))
 
+
 class ViewApplicationTests(unittest.TestCase):
 
     def setUp(self):
     def test_context_no_parent(self):
         self.view.context = self.contained
         self.assertRaises(
-            ValueError, asm.cms.get_application_for_view, self.view)
+            ValueError, get_application_for_view, self.view)
 
     def test_context_is_app(self):
         self.view.context = self.application
         self.assertEquals(
-            self.application, asm.cms.get_application_for_view(self.view))
+            self.application, get_application_for_view(self.view))
 
     def test_context_parent_is_app(self):
         self.view.context = self.contained
         self.view.context.__parent__ = self.application
         self.assertEquals(
-            self.application, asm.cms.get_application_for_view(self.view))
+            self.application, get_application_for_view(self.view))
 
 
 class ViewResolveURLsTests(asm.cms.testing.FunctionalTestCase):

src/asm/cms/testutils.py

 import xml.etree.ElementTree as etree
 import xml.parsers.expat
 
+
 class TestCase(unittest.TestCase):
     """Python's unittest.TestCase extended with additional assert functions."""
 

src/asm/cms/typography.py

-import lxml.etree
-import grok
-import asm.cms.interfaces
-
-# These tags are never filtered.
-WHITELIST_TAGS =  ['pre', 'script', 'object', 'embed', 'param', 'div',
-                   'img', 'body', 'html', 'head', 'javascript',
-                   'stupidcontainer', 'br']
-
-# XXX disabled currently as this causes problems in production.
-#@grok.subscribe(asm.cms.interfaces.IHTMLPage, grok.IObjectModifiedEvent)
-#@grok.subscribe(asm.cms.interfaces.IHTMLPage, grok.IObjectAddedEvent)
-#def paragraph_checking(page, event=None):
-#    clean_typography(page)
-
-
-def remove_empty_paragraph(page, element):
-    remove = lambda: element.getparent().remove(element)
-    if len(element):
-        pass
-    elif element.text is None:
-        remove()
-    elif element.text.strip() == '':
-        remove()
-
-
-def remove_repeated_title_from_content(page, element):
-    if element.tag != 'h1':
-        return
-    if element.text is None:
-        return
-    h1 = element.text.strip().lower()
-    title = page.title.strip().lower()
-    if h1 == title:
-        element.getparent().remove(element)
-
-
-def clean_typography(page):
-    html = page.content
-    parser = lxml.etree.HTMLParser()
-    document = (
-        '<stupidcontainer>%s</stupidcontainer>' % html)
-    document = lxml.etree.fromstring(document, parser)
-    for element in document.getiterator():
-        if element.tag in WHITELIST_TAGS:
-            continue
-        for filter in [remove_empty_paragraph,
-                       remove_repeated_title_from_content]:
-            filter(page, element)
-
-    result = lxml.etree.tostring(document.xpath('//stupidcontainer')[0],
-        pretty_print=True)
-    result = result.replace('<stupidcontainer>', '')
-    result = result.replace('</stupidcontainer>', '')
-    # This is the case when there's nothing to return
-    result = result.replace('<stupidcontainer/>', '')
-    result = result.strip()
-    page.content = result

src/asm/cms/utils.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import lxml.etree
 import re
 import time
         content)
     return lxml.etree.fromstring(document, parser)
 
+
 def fragment_from_tree(document):
     result = lxml.etree.tostring(
         document.xpath('//stupidcontainerwrappercafebabe')[0],
     result = result.replace('</stupidcontainerwrappercafebabe>', '')
     return result.strip()
 
+
 def rewrite_urls(content, visitor):
     """Rewrite URLs using a visitor.
 

src/asm/cmsui/__init__.py

-# Make this a Python package
+import grok
 
-import grok
 
 def get_path(self, item, include_self=False):
     "Return the list of pages leading to this edition."

src/asm/cmsui/asset.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import ZODB.blob
 import asm.cms.asset
 import asm.cms.utils
 import asm.cmsui.interfaces
 import cgi
 import grok
-import magic
 import os
 import urllib
 import zope.app.form.browser.textwidgets
             f.close()
         return value
 
+
 class Edit(asm.cmsui.form.EditionEditForm):
 
     grok.layer(asm.cmsui.interfaces.ICMSSkin)
     def update(self):
         self.response.setHeader('Content-Type', self.context.content_type)
 
-        modified = asm.cms.utils.datetime_to_http_timestamp(self.context.modified)
+        modified = asm.cms.utils.datetime_to_http_timestamp(
+            self.context.modified)
         self.response.setHeader('Last-Modified', modified)
 
         filedata = open(self.context.content.committed())
         self.response.setHeader("Content-Transfer-Encoding", "binary")
         self.response.setHeader("Content-Description", "File Transfer")
         filename = urllib.quote_plus(self.context.page.__name__)
-        self.response.setHeader("Content-Disposition", "attachment; filename=%s" % filename)
+        self.response.setHeader(
+            "Content-Disposition", "attachment; filename=%s" % filename)
         return super(Download, self).update(*args, **kw)
 
     def render(self, *args, **kw):
 
     return result
 
+
 class TextIndexing(grok.Adapter):
 
     zope.interface.implements(asm.cms.interfaces.ISearchableText)
     def __init__(self, asset):
         self.body = searchable_text(asset)
 
+
 class SearchPreview(grok.View):
 
     def update(self, q):

src/asm/cmsui/base.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
+import asm.cmsui.interfaces
 import grok
-import asm.cmsui.interfaces
 import zope.interface
 
 

src/asm/cmsui/cms.py

-# Copyright (c) 2010-2012 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.cms
 import asm.cms.interfaces
 import asm.cmsui.form

src/asm/cmsui/edition.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.interfaces
 import asm.cmsui.base
 class ImagePicker(grok.View):
     grok.context(asm.cms.edition.Edition)
     grok.name('image-picker')
-
-
-

src/asm/cmsui/form.py

-# Copyright (c) 2008-2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.interfaces
 import asm.cmsui.interfaces
 import grok

src/asm/cmsui/homepage.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.interfaces
 import asm.cmsui.form
 import asm.cmsui.interfaces

src/asm/cmsui/htmlpage.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.htmlpage
+import asm.cmsui.form
 import asm.cmsui.interfaces
 import asm.cmsui.retail
-import asm.cmsui.form
 import asm.cmsui.tinymce
 import cgi
 import grok
         # Select limited amount of characters
         focus = text.lower().find(self.keyword.lower())
         if focus == -1:
-            return cgi.escape(text[:2*self.PREVIEW_AMOUNT])
+            return cgi.escape(text[:2 * self.PREVIEW_AMOUNT])
         text = text[
             max(focus - self.PREVIEW_AMOUNT, 0):(focus + self.PREVIEW_AMOUNT)]
 
             tuple(map(cgi.escape, [pre, keyword, post]))
         return text
 
+
 class ExtendedPageActions(grok.Viewlet):
 
     grok.viewletmanager(asm.cmsui.base.ExtendedPageActions)

src/asm/cmsui/importer.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.cms
 import asm.cms.importer
 import asm.cmsui.base
 import transaction
 import zope.interface
 
+
 class ImportActions(grok.Viewlet):
 
     grok.viewletmanager(asm.cmsui.base.NavigationToolActions)
         if len(errors) > 0:
             self.flash(u"Aborted import due to following errors:")
         if len(errors) > self.display_max_errors:
-            self.flash(u"Too many errors detected. Displaying the first %d errors." % self.display_max_errors)
+            self.flash(u"Too many errors detected. "
+                       u"Displaying the first %d errors." %
+                       self.display_max_errors)
         for error in errors[:self.display_max_errors]:
             self.flash(error, "warning")
 

src/asm/cmsui/interfaces.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import grok
 
 

src/asm/cmsui/layout.py

-#prox Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.interfaces
 import asm.cmsui.base

src/asm/cmsui/news.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cmsui.form
 import asm.cmsui.retail
 import asm.cms.news

src/asm/cmsui/page.py

              'id': page_id,
              })
 
+
 class Rename(grok.View):
 
     grok.context(asm.cms.interfaces.IPage)
 
         iids = zope.component.getUtility(zope.intid.interfaces.IIntIds)
         open_page = iids.getObject(int(open_page_id))
-        self.open_edition = asm.cms.edition.select_edition(open_page, self.request)
+        self.open_edition = asm.cms.edition.select_edition(
+            open_page, self.request)
 
         parent = self.context.__parent__
         if new_name in parent:

src/asm/cmsui/preview.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
+import asm.cmsui.interfaces
 import grok
+import zope.component
 import zope.interface
-import asm.cmsui.interfaces
-import zope.component
 import zope.intid
 
 

src/asm/cmsui/public/layout.py

-#prox Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.interfaces
 import asm.cmsui.base
 import asm.cmsui.interfaces
 import grok
-import megrok.pagelet
-import z3c.flashmessage.interfaces
 import zope.interface
 import zope.security
 
 
-class PublicLayoutHelper(grok.View):
+class LayoutHelper(grok.View):
+    grok.baseclass()
     grok.context(zope.interface.Interface)
-    grok.layer(asm.cmsui.interfaces.IRetailSkin)
+
+    # A helper class to get access to the static directory from the layout and
+    # to accumulate some view-based helper functions needed all around.
+
+    def current_language(self):
+        cookie_lang = self.request.cookies.get('asm.translation.lang')
+        if cookie_lang in asm.translation.translation.current():
+            return cookie_lang
+        return asm.translation.translation.fallback()
 
     def render(self):
         return ''
+
+
+class PublicLayoutHelper(LayoutHelper):
+    grok.layer(asm.cmsui.interfaces.IRetailSkin)

src/asm/cmsui/redirect.py

-# Copyright (c) 2011 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.redirect
 import asm.cmsui.interfaces
 import zope.publisher.interfaces.browser
 import zope.traversing.browser.interfaces
 
+
 grok.context(asm.cms.redirect.Redirect)
 
+
 class Edit(asm.cmsui.form.EditionEditForm):
 
     grok.layer(asm.cmsui.interfaces.ICMSSkin)
     main_fields = grok.AutoFields(asm.cms.redirect.Redirect).select(
         'title', 'target_url')
 
+
 class Index(grok.View):
 
     grok.layer(grok.IDefaultBrowserLayer)
         self.redirect(self.context.target_url, trusted=True)
 
     def render(self):
-        return '<a href="%s">%s</a>' % (self.context.target_url, self.context.target_url)
+        return '<a href="%s">%s</a>' % (
+            self.context.target_url, self.context.target_url)
+
 
 class RedirectAbsoluteUrl(grok.MultiAdapter):
     grok.adapts(

src/asm/cmsui/replace.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
+import asm.cms.cms
+import asm.cmsui.base
+import asm.cmsui.interfaces
+import grok
 import megrok.pagelet
-import grok
-import asm.cms.cms
-import asm.cmsui.interfaces
-import asm.cmsui.base
 import zope.interface
 
 grok.context(asm.cms.cms.CMS)
 
+
 class SearchAndReplace(megrok.pagelet.Pagelet):
     """Present the user a form to allow entering search and replace terms."""
 

src/asm/cmsui/retail.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.interfaces
 import asm.cmsui.interfaces
 import grok
 import megrok.pagelet
+import zope.app.folder.interfaces
 import zope.app.publication.interfaces
 import zope.interface
-import zope.app.folder.interfaces
 
 
 class Layout(megrok.pagelet.Layout):
         return self.context.page
 
 
-@grok.adapter(asm.cms.interfaces.IEdition, asm.cmsui.interfaces.IRetailBaseSkin)
+@grok.adapter(asm.cms.interfaces.IEdition,
+              asm.cmsui.interfaces.IRetailBaseSkin)
 @grok.implementer(zope.traversing.browser.interfaces.IAbsoluteURL)
 def edition_url(edition, request):
     return zope.component.getMultiAdapter(

src/asm/cmsui/search.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
+from asm.cms.edition import select_edition
 import asm.cms.cms
 import asm.cmsui.interfaces
 import grok
 import hurry.query.query
+import megrok.pagelet
 import simplejson
-import megrok.pagelet
 import zope.component
 import zope.index.text.parsetree
 
+
 class Search(megrok.pagelet.Pagelet):
 
     grok.context(asm.cms.cms.CMS)
 
         self.results = []
         for result in results:
-            if result is asm.cms.edition.select_edition(result.page, self.request):
+            if result is select_edition(result.page, self.request):
                 self.results.append(result)
 
 

src/asm/cmsui/security.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import grok
 
 

src/asm/cmsui/testing.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.cms
 import gocept.selenium.ztk
 import os.path

src/asm/cmsui/tests/test_adding.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cmsui.testing
 import transaction
 

src/asm/cmsui/tests/test_asset.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
-# See also LICENSE.txt
-
 import asm.cmsui.testing
 import asm.cms.page
 import transaction
 
     def setUp(self):
         super(Asset, self).setUp()
-        self.cms['asset'] = asset = asm.cms.page.Page('asset')
+        self.cms['asset'] = asm.cms.page.Page('asset')
         transaction.commit()
         self.selenium.open('http://%s/++skin++cms/cms/asset/edition-/@@edit' %
                            self.selenium.server)
         s.open('http://%s/++skin++cms/cms/asset/edition-/@@edit' % s.server)
         s.click('xpath=//input[@type="button" and @value="Download"]')
         self.assertEquals(
-            'http://%s/++skin++cms/cms/asset/edition-/@@edit' % s.server
-            ,s.getLocation())
+            'http://%s/++skin++cms/cms/asset/edition-/@@edit' % s.server,
+            s.getLocation())

src/asm/cmsui/tests/test_cmsui.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.page
 import asm.cmsui.testing
 import grok
 import transaction
-import unittest
 import zope.event
 
 
     def test_change_page_type(self):
         s = self.selenium
         s.assertNotVisible('xpath=//input[@value="Change page type"]')
-        s.click('//h3[contains(text(), "Page")]/following-sibling::div[@class="opener"]')
+        s.click('//h3[contains(text(), "Page")]/'
+                'following-sibling::div[@class="opener"]')
         s.assertVisible('xpath=//input[@value="Change page type"]')
         s.clickAndWait('xpath=//input[@value="Change page type"]')
-        s.click('id=form.type.0') # Redirect section
+        s.click('id=form.type.0')  # Redirect section
         s.clickAndWait('name=form.actions.change')
         self.assertEquals(
             'http://%s/++skin++cms/cms/edition-/@@edit' % s.server,

src/asm/cmsui/tests/test_formats.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
-import unittest
 import asm.cmsui.format
 import datetime
+import unittest
 
 
 class FormatTests(unittest.TestCase):

src/asm/cmsui/tests/test_import.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cmsui.testing
 
 
     def test_import_form_available(self):
         s = self.selenium
         s.click('css=.toggle-navigation')
-        s.click("xpath=//h3[contains(text(),'Tools')]/following-sibling::div[@class='opener']")
+        s.click('xpath=//h3[contains(text(),\'Tools\')]'
+                '/following-sibling::div[@class=\'opener\']')
         s.assertVisible("xpath=//button[contains(text(), 'Import content')]")
         s.clickAndWait("xpath=//button[contains(text(), 'Import content')]")

src/asm/cmsui/tests/test_preview.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cmsui.testing
-import zope.testbrowser.testing
 
 
 class PreviewTests(asm.cmsui.testing.SeleniumTestCase):
     def test_preview_not_broken(self):
         # Very simple smoke test to ensure that the preview template actually
         # renders. I've seen this break when renaming static resources.
-        self.selenium.open('http://mgr:mgrpw@%s/++skin++cms/cms/@@preview-window' %
-                           self.selenium.server)
+        self.selenium.open(
+            'http://mgr:mgrpw@%s/++skin++cms/cms/@@preview-window' %
+            self.selenium.server)

src/asm/cmsui/tests/test_replace.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.cms
 import asm.cms.htmlpage
 import asm.cms.replace
 import asm.cmsui.testing
 import transaction
-import unittest
 
 
 class ReplaceSelenium(asm.cmsui.testing.SeleniumTestCase):

src/asm/cmsui/tests/test_security.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.testing
 import asm.cmsui.interfaces
 import unittest
     def test_cms_skin_protected(self):
         # All views in the CMS skin are supposed to be protected by
         # 'asm.cms.EditContent' permission.
-        for registration in zope.component.globalSiteManager.registeredAdapters():
+        adapters = zope.component.globalSiteManager.registeredAdapters()
+        for registration in adapters:
             if len(registration.required) != 2:
                 continue
             if registration.required[1] is not asm.cmsui.interfaces.ICMSSkin:

src/asm/cmsui/tinymce.py

-# Copyright (c) 2009 gocept gmbh & co. kg
-# See also LICENSE.txt
-
-import zope.app.form.browser.textwidgets
 import asm.cms.interfaces
 import grok
+import zope.app.form.browser.textwidgets
 
 
 class TinyMCEWidget(zope.app.form.browser.textwidgets.TextAreaWidget):
         self.cssClass += ' %s' % self.mce_class
         return super(TinyMCEWidget, self).__call__()
 
+
 class TinyMCEWidgetSmall(TinyMCEWidget):
 
     mce_class = 'mceEditorSmall'

src/asm/cmsui/tree.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import StringIO
 import asm.cms.edition
 import asm.cmsui.interfaces
 # We don't have any children.
 BRANCH_STATE_NONE = None
 
+
 class Tree(grok.View):
 
     grok.context(grok.Application)   # XXX Meh.
             page = iids.getObject(int(page_id))
             self.open_page = page
 
-
     def _get_page_data(self, page):
         intids = zope.component.getUtility(zope.intid.IIntIds)
         edition = asm.cms.edition.select_edition(page, self.request)
 
         return pages
 
-
     def tree(self):
         pages = []
         # When we are opening the tree for the first time, we don't have

src/asm/contact/contact.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import asm.cms.interfaces
 import asm.cms
 import asm.contact.interfaces

src/asm/contact/interfaces.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import zope.interface
 import zope.schema
 
     name = zope.schema.TextLine(title=u'Your name')
     subject = zope.schema.TextLine(title=u'Subject')
     message = zope.schema.Text(title=u'Your message')
-

src/asm/contact/testing.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import os.path
 import zope.app.testing.functional
 

src/asm/layoutpage/dynamic.py

-import grok
+from asm.cms.edition import find_editions
+import asm.cms.edition
 import asm.cms.interfaces
 import asm.cmsui.interfaces
-import asm.cms.edition
+import grok
 
 
 class TileNavigation(grok.View):
     def update(self):
         self.rows = []
         row = []
-        for edition in asm.cms.edition.find_editions(self.context.page, self.request,
-                recurse=False):
+        editions = find_editions(self.context.page, self.request,
+                                 recurse=False)
+        for edition in editions:
             if edition.has_tag('hide-navigation'):
                 continue
             if len(row) == 3:
 
 NAVTREE_MAX_LEVELS = 999
 
+
 def _create_navigation_subtree(active, root_page, levels, request):
     if levels < 0:
         return
         tree['class'].add('active')
         if root_page.type not in ['news']:
             for child in root_page.subpages:
-                sub_tree = _create_navigation_subtree(active, child, levels - 1, request)
+                sub_tree = _create_navigation_subtree(
+                    active, child, levels - 1, request)
                 if sub_tree:
                     tree['subpages'].append(sub_tree)
     if 'active' in tree['class'] and not tree['subpages']:
     def update(self):
         self.section = self.find_section()
         self.subsections = []
-        for edition in asm.cms.edition.find_editions(self.section, self.request,
-                recurse=False):
+        editions = find_editions(self.section, self.request, recurse=False)
+        for edition in editions:
             if edition.has_tag('hide-navigation'):
                 continue
             self.subsections.append(edition)
 
     def tree(self):
         root = self.find_section()
-        tree = _create_navigation_subtree(self.active, root, NAVTREE_MAX_LEVELS, self.request)
+        tree = _create_navigation_subtree(
+            self.active, root, NAVTREE_MAX_LEVELS, self.request)
         return tree['subpages']
 
 
     def tree(self):
         root_edition = self.find_subsection()
         root = root_edition.page
-        tree = _create_navigation_subtree(self.active, root, NAVTREE_MAX_LEVELS, self.request)
+        tree = _create_navigation_subtree(
+            self.active, root, NAVTREE_MAX_LEVELS, self.request)
         return tree['subpages']
 
 

src/asm/layoutpage/layoutpage.py

 
     def render(self, request, context, partial_render):
         template = LayoutTemplate(
-            self.layout, lambda name:self._lookup(name, request, context,
-                partial_render))
+            self.layout, lambda name: self._lookup(
+                name, request, context, partial_render))
         return template()
 
 
 
     def __call__(self):
         return self.MARKER_PATTERN.sub(
-            lambda match:self.value_lookup(match.groups()[0]),
+            lambda match: self.value_lookup(match.groups()[0]),
             self.template)
 
 
          provided=asm.layoutpage.interfaces.ILayoutPage, name=page.__name__)
 
 
-
 @grok.subscribe(asm.cms.interfaces.IPage, grok.IObjectRemovedEvent)
 def ensure_page_is_not_local_utility(obj, event):
     try:
-        registered_page = zope.component.getUtility(
+        zope.component.getUtility(
             asm.layoutpage.interfaces.ILayoutPage, name=obj.__name__)
     except LookupError:
         pass

src/asm/layoutpage/layouts.py

 import grok
 
 
-
 class DefaultLayout(asm.layoutpage.layoutpage.Layout, grok.GlobalUtility):
     grok.provides(asm.layoutpage.interfaces.ILayoutPage)
     grok.name('default')

src/asm/layoutpage/selection.py

 
     zope.interface.taggedValue('label', u'Layout')
     zope.interface.taggedValue(
-        'description', u'Select a page layout to use when displaying this page.')
+        'description',
+        u'Select a page layout to use when displaying this page.')
 
     layout = zope.schema.Choice(
         title=u'Layout', required=False,
         source=LayoutSource())
 
 
-
-
 class LayoutAnnotation(grok.Annotation):
     grok.implements(ILayoutSelection)
     grok.provides(ILayoutSelection)
     grok.context(asm.cms.interfaces.IEdition)
 
-    layout = '' # automatic default
+    layout = ''  # automatic default
 
     def copyFrom(self, other):
         self.layout = other.layout

src/asm/manual/skin.py

 import asm.cms
 import asm.cmsui.retail
 import asm.cmsui.interfaces
+import asm.cmsui.public.layout
 import datetime
 import grok
 import megrok.pagelet
     megrok.pagelet.template('layout.pt')
 
 
-class LayoutHelper(grok.View):
-    grok.context(zope.interface.Interface)
+class LayoutHelper(asm.cmsui.public.layout.LayoutHelper):
     grok.layer(ISkin)
 
     def current_events(self):
-        if 'program' not in self.application or 'schedule' not in self.application['program']:
+        if 'program' not in self.application:
+            raise StopIteration()
+        if 'schedule' not in self.application['program']:
             raise StopIteration()
         schedule = asm.cms.edition.select_edition(
             self.application['program']['schedule'], self.request)
         except:
             return []
 
-    # A helper class to get access to the static directory in this module from
-    # the layout.
-
-    def render(self):
-        return ''
-
 
 class Navtree(grok.View):
     grok.layer(ISkin)
 
     def news(self, tag):
         if 'news' not in self.context.page:
-           raise StopIteration() 
-        
+            raise StopIteration()
+
         news_edition = asm.cms.edition.select_edition(
             self.context.page['news'], self.request)
         for item in news_edition.list():

src/asm/manual/testing.py

-# Copyright (c) 2009 Assembly Organizing
-# See also LICENSE.txt
-
 import os.path
 import zope.app.testing.functional
 

src/asm/mediagallery/asset.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
-import grok
 import asm.cms.asset
 import asm.cmsui.base
+import grok
 
 
 class ViewGallery(asm.cmsui.retail.Pagelet):

src/asm/mediagallery/externalasset.py

-# Copyright (c) 2010 gocept gmbh & co. kg
-# See also LICENSE.txt
-
 import asm.cms.edition
 import asm.cms.importer
+import asm.cmsui.form
+import asm.cmsui.retail
 import asm.mediagallery.interfaces
 import grok
 import persistent
+import zope.app.form.browser.objectwidget
 import zope.interface
<