Completed
Push — master ( 06f394...69db82 )
by Asif
01:41 queued 14s
created

crudbuilder.import_crud()   A

Complexity

Conditions 1

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 1
dl 0
loc 20
rs 9.4286
1
import re
2
import string
3
4
from crudbuilder.exceptions import CrudModuleNotExit
5
6
__all__ = ['plural', 'mixedToUnder', 'capword', 'lowerword', 'underToMixed']
7
8
# http://code.activestate.com/recipes/82102-smart-pluralisation-english/
9
10
11
def plural(text):
12
    """
13
        >>> plural('activity')
14
        'activities'
15
    """
16
    aberrant = {
17
        'knife': 'knives',
18
        'self': 'selves',
19
        'elf': 'elves',
20
        'life': 'lives',
21
        'hoof': 'hooves',
22
        'leaf': 'leaves',
23
        'echo': 'echoes',
24
        'embargo': 'embargoes',
25
        'hero': 'heroes',
26
        'potato': 'potatoes',
27
        'tomato': 'tomatoes',
28
        'torpedo': 'torpedoes',
29
        'veto': 'vetoes',
30
        'child': 'children',
31
        'woman': 'women',
32
        'man': 'men',
33
        'person': 'people',
34
        'goose': 'geese',
35
        'mouse': 'mice',
36
        'barracks': 'barracks',
37
        'deer': 'deer',
38
        'nucleus': 'nuclei',
39
        'syllabus': 'syllabi',
40
        'focus': 'foci',
41
        'fungus': 'fungi',
42
        'cactus': 'cacti',
43
        'phenomenon': 'phenomena',
44
        'index': 'indices',
45
        'appendix': 'appendices',
46
        'criterion': 'criteria',
47
48
49
    }
50
51
    if text in aberrant:
52
        result = '%s' % aberrant[text]
53
    else:
54
        postfix = 's'
55
        if len(text) > 2:
56
            vowels = 'aeiou'
57
            if text[-2:] in ('ch', 'sh'):
58
                postfix = 'es'
59
            elif text[-1:] == 'y':
60
                if (text[-2:-1] in vowels) or (text[0] in string.uppercase):
61
                    postfix = 's'
62
                else:
63
                    postfix = 'ies'
64
                    text = text[:-1]
65
            elif text[-2:] == 'is':
66
                postfix = 'es'
67
                text = text[:-2]
68
            elif text[-1:] in ('s', 'z', 'x'):
69
                postfix = 'es'
70
71
        result = '%s%s' % (text, postfix)
72
    return result
73
74
75
# http://www.sqlobject.org/sqlobject/styles.py.html
76
class Style(object):
77
78
    """
79
    The base Style class, and also the simplest implementation.  No
80
    translation occurs -- column names and attribute names match,
81
    as do class names and table names (when using auto class or
82
    schema generation).
83
    """
84
85
    def __init__(self, pythonAttrToDBColumn=None,
86
                 dbColumnToPythonAttr=None,
87
                 pythonClassToDBTable=None,
88
                 dbTableToPythonClass=None,
89
                 idForTable=None,
90
                 longID=False):
91
        if pythonAttrToDBColumn:
92
            self.pythonAttrToDBColumn = lambda a, s = self: pythonAttrToDBColumn(
93
                s, a)
94
        if dbColumnToPythonAttr:
95
            self.dbColumnToPythonAttr = lambda a, s = self: dbColumnToPythonAttr(
96
                s, a)
97
        if pythonClassToDBTable:
98
            self.pythonClassToDBTable = lambda a, s = self: pythonClassToDBTable(
99
                s, a)
100
        if dbTableToPythonClass:
101
            self.dbTableToPythonClass = lambda a, s = self: dbTableToPythonClass(
102
                s, a)
103
        if idForTable:
104
            self.idForTable = lambda a, s = self: idForTable(s, a)
105
        self.longID = longID
106
107
    def pythonAttrToDBColumn(self, attr):
108
        return attr
109
110
    def dbColumnToPythonAttr(self, col):
111
        return col
112
113
    def pythonClassToDBTable(self, className):
114
        return className
115
116
    def dbTableToPythonClass(self, table):
117
        return table
118
119
    def idForTable(self, table):
120
        if self.longID:
121
            return self.tableReference(table)
122
        else:
123
            return 'id'
124
125
    def pythonClassToAttr(self, className):
126
        return lowerword(className)
127
128
    def instanceAttrToIDAttr(self, attr):
129
        return attr + "ID"
130
131
    def instanceIDAttrToAttr(self, attr):
132
        return attr[:-2]
133
134
    def tableReference(self, table):
135
        return table + "_id"
136
137
138
class MixedCaseUnderscoreStyle(Style):
139
140
    """
141
    This is the default style.  Python attributes use mixedCase,
142
    while database columns use underscore_separated.
143
    """
144
145
    def pythonAttrToDBColumn(self, attr):
146
        return mixedToUnder(attr)
147
148
    def dbColumnToPythonAttr(self, col):
149
        return underToMixed(col)
150
151
    def pythonClassToDBTable(self, className):
152
        return className[0].lower() \
153
            + mixedToUnder(className[1:])
154
155
    def dbTableToPythonClass(self, table):
156
        return table[0].upper() \
157
            + underToMixed(table[1:])
158
159
    def pythonClassToDBTableReference(self, className):
160
        return self.tableReference(self.pythonClassToDBTable(className))
161
162
    def tableReference(self, table):
163
        return table + "_id"
164
165
DefaultStyle = MixedCaseUnderscoreStyle
166
167
168
class MixedCaseStyle(Style):
169
170
    """
171
    This style leaves columns as mixed-case, and uses long
172
    ID names (like ProductID instead of simply id).
173
    """
174
175
    def pythonAttrToDBColumn(self, attr):
176
        return capword(attr)
177
178
    def dbColumnToPythonAttr(self, col):
179
        return lowerword(col)
180
181
    def dbTableToPythonClass(self, table):
182
        return capword(table)
183
184
    def tableReference(self, table):
185
        return table + "ID"
186
187
defaultStyle = DefaultStyle()
188
189
190
def getStyle(soClass, dbConnection=None):
191
    if dbConnection is None:
192
        if hasattr(soClass, '_connection'):
193
            dbConnection = soClass._connection
194
    if hasattr(soClass.sqlmeta, 'style') and soClass.sqlmeta.style:
195
        return soClass.sqlmeta.style
196
    elif dbConnection and dbConnection.style:
197
        return dbConnection.style
198
    else:
199
        return defaultStyle
200
201
#
202
# Text utilities
203
#
204
_mixedToUnderRE = re.compile(r'[A-Z]+')
205
206
207
def mixedToUnder(s):
208
    """
209
    Sample:
210
        >>> mixedToUnder("FooBarBaz")
211
        'foo_bar_baz'
212
213
    Special case for ID:
214
        >>> mixedToUnder("FooBarID")
215
        'foo_bar_id'
216
    """
217
    if s.endswith('ID'):
218
        return mixedToUnder(s[:-2] + "_id")
219
    trans = _mixedToUnderRE.sub(mixedToUnderSub, s)
220
    if trans.startswith('_'):
221
        trans = trans[1:]
222
    return trans
223
224
225
def mixedToUnderSub(match):
226
    m = match.group(0).lower()
227
    if len(m) > 1:
228
        return '_%s_%s' % (m[:-1], m[-1])
229
    else:
230
        return '_%s' % m
231
232
233
def capword(s):
234
    """
235
    >>> capword('foo')
236
    'Foo'
237
    """
238
    return s[0].upper() + s[1:]
239
240
241
def lowerword(s):
242
    """
243
    >>> lowerword('Hello')
244
    'hello'
245
    """
246
    return s[0].lower() + s[1:]
247
248
_underToMixedRE = re.compile('_.')
249
250
251
def underToMixed(name):
252
    """
253
    >>> underToMixed('some_large_model_name_perhaps')
254
    'someLargeModelNamePerhaps'
255
256
    >>> underToMixed('exception_for_id')
257
    'exceptionForID'
258
    """
259
    if name.endswith('_id'):
260
        return underToMixed(name[:-3] + "ID")
261
    return _underToMixedRE.sub(lambda m: m.group(0)[1].upper(),
262
                               name)
263
264
265
def model_class_form(name):
266
    """
267
    >>> model_class_form('foo_bar_baz')
268
    'FooBarBaz'
269
    """
270
    return capword(underToMixed(name))
271
272
273
def underToAllCaps(value):
274
    """
275
    >>> underToAllCaps('foo_bar_baz')
276
    'Foo Bar Baz'
277
    """
278
    return ' '.join(map(lambda x: x.title(), value.split('_')))
279
280
281
def import_crud(app):
282
    '''
283
    Import moderator module and register all models it contains with moderation
284
    '''
285
    from django.utils.importlib import import_module
286
    import imp
287
288
    try:
289
        app_path = import_module(app).__path__
290
    except AttributeError:
291
        return None
292
293
    try:
294
        imp.find_module('crud', app_path)
295
    except ImportError:
296
        return None
297
298
    module = import_module("%s.crud" % app)
299
300
    return module
301
302
303
def auto_discover():
304
    '''
305
    Auto register all apps that have module moderator with moderation
306
    '''
307
    from django.conf import settings
308
309
    for app in settings.INSTALLED_APPS:
310
        import_crud(app)
311
312
313
if __name__ == '__main__':
314
    print plural('activity')
315