source: main/waeup.sirp/trunk/src/waeup/sirp/utils/helpers.py @ 5840

Last change on this file since 5840 was 5738, checked in by uli, 14 years ago

Be more verbose.

File size: 7.5 KB
Line 
1"""General helper functions for WAeUP.
2"""
3import os
4import re
5import sys
6import shutil
7import grok
8from zope.component.interfaces import IFactory
9from zope.interface import implementedBy
10
11def removeFileOrDirectory(filepath):
12    """Remove a file or directory.
13
14    Different to :func:`shutil.rmtree` we also accept not existing
15    paths (returning silently) and if a dir turns out to be a regular
16    file, we remove that.
17    """
18    filepath = os.path.abspath(filepath)
19    if not os.path.exists(filepath):
20        return
21    if os.path.isdir(filepath):
22        shutil.rmtree(filepath)
23    else:
24        os.unlink(filepath)
25    return
26
27def copyFileSystemTree(src, dst, overwrite=False, del_old=False):
28    """Copy contents of directory src to directory dst.
29
30    Both directories must exists.
31
32    If `overwrite` is true, any same named objects will be
33    overwritten. Otherwise these files will not be touched.
34
35    If `del_old` is true, copied files and directories will be removed
36    from the src directory.
37
38    This functions returns a list of non-copied files.
39
40    Unix hidden files and directories (starting with '.') are not
41    processed by this function.
42    """
43    if not os.path.exists(src):
44        raise ValueError('source path does not exist: %s' % src)
45    if not os.path.exists(dst):
46        raise ValueError('destination path does not exist: %s' % dst)
47    if not os.path.isdir(src):
48        raise ValueError('source path is not a directory: %s' % src)
49    if not os.path.isdir(dst):
50        raise ValueError('destination path is not a directory: %s' % dst)
51    not_copied = []
52    for item in os.listdir(src):
53        if item.startswith('.'):
54            continue # We do not copy hidden stuff...
55        itemsrc = os.path.join(src, item)
56        itemdst = os.path.join(dst, item)
57
58        if os.path.exists(itemdst):
59            if overwrite is True:
60                removeFileOrDirectory(itemdst)
61            else:
62                not_copied.append(item)
63                continue
64       
65        if os.path.isdir(itemsrc):
66            shutil.copytree(itemsrc, itemdst)
67        else:
68            shutil.copy2(itemsrc, itemdst)
69        if del_old:
70            removeFileOrDirectory(itemsrc)
71    return not_copied
72
73
74def getInnerHTMLPart(html_code):
75    """Return the 'inner' part of a complete HTML snippet.
76
77    If there is a form part, get this.
78
79    If there is no form part, try to return the body part contents.
80
81    If there is no body, return as-is.
82
83    Let's see how that works. If we deliver some doc with form, we
84    will get that form only:
85
86       >>> doc = '<html><form>My Form</form>Outside the form</html>'
87       >>> getInnerHTMLPart(doc)
88       '<form>My Form</form>'
89
90    No form? Then seek for a body part and get the contents:
91
92       >>> doc = '<html><body>My Body</body>Trailing Trash</html>'
93       >>> getInnerHTMLPart(doc)
94       'My Body'
95
96    If none of these is included, return what we got:
97
98       >>> doc = '<html>without body nor form</html>'
99       >>> getInnerHTMLPart(doc)
100       '<html>without body nor form</html>'
101
102    """
103
104    try:
105        result = re.match('^.+(<form[^\>]*>.*</form>).+$', html_code,
106                          re.DOTALL).groups()[0]
107        return result
108    except AttributeError:
109        # No <form> part included
110        try:
111            result = re.match('^.+<body[^\>]*>(.*)</body>.*$', html_code,
112                              re.DOTALL).groups()[0]
113            return result
114        except AttributeError:
115            # No <form> and no <body> tag...
116            pass
117    return html_code
118
119def getName(context):
120    """Construct a name out of an object with prefix and title.
121
122    The `context` has to provide `title_prefix` and `title`
123    attributes.
124
125        >>> from waeup.sirp.utils.helpers import getName
126        >>> class FakeObject(object):
127        ...     title_prefix = 'department'
128        ...     title = 'Strange Things'
129        >>> getName(FakeObject())
130        'Department of Strange Things'
131
132    As we can see in the result the `title_prefix` is rendered
133    uppercase.
134       
135    """
136    prefix = context.title_prefix
137    prefix = prefix[0].upper() + prefix[1:]
138    return '%s of %s' % (prefix, context.title)
139
140class FactoryBase(grok.GlobalUtility):
141    """A factory for things.
142
143    This is a baseclass for easier creation of factories. Factories
144    are utilities that are registered under a certain name and return
145    instances of certain classes when called.
146
147    In :mod:`waeup.sirp` we use factories extensively for
148    batching. While processing a batch some importer looks up a
149    factory to create real-world instances that then get filled with
150    data from imported CSV files.
151
152    To get rid of reimplementing the same stuff over and over again,
153    most notably the methods defined here, we offer this base class
154    (which will *not* be registered as a factory itself).
155
156    Real factories can then be created like this:
157
158       >>> import grok
159       >>> from waeup.sirp.utils.helpers import FactoryBase
160       >>> class MyObject(object):
161       ...   # Some class we want to get instances of.
162       ...   pass
163       >>> class MyObjectFactory(FactoryBase):
164       ...   # This is the factory for MyObject instances
165       ...   grok.name(u'waeup.sirp.factory.MyObject')
166       ...   factory = MyObject
167
168    That's it. It is essential to set the ``factory`` attribute, which
169    will determine the class of which instances should be created when
170    called. The given name must even be unique amongst all utilities
171    registered during runtime. While you can pick any name you like
172    you might want to prepend ``waeup.sirp.factory.`` to the name
173    string to make sure it does not clash with names of other
174    utilities one day.
175
176    Before all this works we have to grok the baseclass once and our
177    freshly defined factory. This executes all the component
178    registration stuff we don't want to do ourselves. In daily use
179    this is done automatically on startup of a :mod:`waeup.sirp`
180    system.
181   
182       >>> grok.testing.grok('waeup.sirp.utils.helpers')
183       >>> grok.testing.grok_component(
184       ...    'MyObjectFactory', MyObjectFactory
185       ...  )
186       True
187
188    After grokking we (and importers) can create objects without
189    knowing about the location of the real class definition, just by
190    the factory name:
191
192       >>> from zope.component import createObject
193       >>> obj = createObject('waeup.sirp.factory.MyObject')
194       >>> isinstance(obj, MyObject)
195       True
196
197    We can also use the regular utility lookups to find our new
198    factory:
199
200       >>> from zope.component import getUtility
201       >>> from zope.component.interfaces import IFactory
202       >>> factory = getUtility(
203       ...   IFactory, name='waeup.sirp.factory.MyObject'
204       ...   )
205       >>> isinstance(factory, MyObjectFactory)
206       True
207
208    And this factory generates `MyObject` instances:
209
210       >>> obj = factory()
211       >>> isinstance(obj, MyObject)
212       True
213
214    """
215    grok.baseclass() # Do not grok this class, do not register us.
216    grok.implements(IFactory)
217    # You can override any of the following attributes in derived
218    # classes. The `grok.name` setting *must* even be set to some
219    # unique value.
220    grok.name(u'waeup.Factory')
221    title = u"Create instances of ``factory``.",
222    description = u"This factory instantiates new applicant instances."
223    factory = None
224
225    def __call__(self, *args, **kw):
226        """The main factory function.
227
228        Returns an instance of the requested object.
229        """
230        return self.factory()
231
232    def getInterfaces(self):
233        # Required by IFactory
234        return implementedBy(self.factory)
Note: See TracBrowser for help on using the repository browser.