Merge lp:~ricardokirkner/django-configglue/tox into lp:django-configglue
- tox
- Merge into trunk
Proposed by
Ricardo Kirkner
Status: | Merged |
---|---|
Approved by: | Ricardo Kirkner |
Approved revision: | 59 |
Merged at revision: | 43 |
Proposed branch: | lp:~ricardokirkner/django-configglue/tox |
Merge into: | lp:django-configglue |
Diff against target: |
1016 lines (+674/-72) 13 files modified
django_configglue/__init__.py (+2/-1) django_configglue/management/commands/settings.py (+1/-1) django_configglue/schema.py (+512/-18) django_configglue/tests/helpers.py (+30/-13) django_configglue/tests/settings.py (+5/-2) django_configglue/tests/test_configglue.py (+42/-20) django_configglue/tests/test_settings.py (+13/-11) django_configglue/utils.py (+1/-0) testproject/main-12.cfg (+12/-0) testproject/main.cfg (+0/-1) testproject/testrunner.py (+3/-5) tox (+6/-0) tox.ini (+47/-0) |
To merge this branch: | bzr merge lp:~ricardokirkner/django-configglue/tox |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Michael Foord (community) | Approve | ||
Review via email: mp+57378@code.launchpad.net |
Commit message
use tox to test all major django versions
Description of the change
This branch adds support for testing django_configglue against all major django versions using tox.
Existing tests have now been made to run against versions
- 1.0.2 final
- 1.0.4
- 1.1.2
- 1.1.4
- 1.2.5
- 1.3
using python 2.6.
Adding more tests and testing against other versions of Python is left for future work.
How to test
===========
Simply run
./tox
To post a comment you must log in.
Revision history for this message
Łukasz Czyżykowski (lukasz-czyzykowski) wrote : | # |
Revision history for this message
Michael Foord (mfoord) wrote : | # |
We need a better solution than deepcopying, but it is a hard problem. Other than that great.
review:
Approve
- 58. By Ricardo Kirkner
-
fixed small style issue per review
- 59. By Ricardo Kirkner
-
fixed style issues per review
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'django_configglue/__init__.py' |
2 | --- django_configglue/__init__.py 2011-01-10 21:43:27 +0000 |
3 | +++ django_configglue/__init__.py 2011-04-13 17:14:29 +0000 |
4 | @@ -42,7 +42,8 @@ |
5 | options, args = parser.parse_args(self.argv) |
6 | handle_default_options(options) |
7 | except: |
8 | - pass # Ignore any option errors at this point. |
9 | + # Ignore any option errors at this point. |
10 | + args = self.argv |
11 | |
12 | try: |
13 | subcommand = self.argv[1] |
14 | |
15 | === modified file 'django_configglue/management/commands/settings.py' |
16 | --- django_configglue/management/commands/settings.py 2011-01-10 21:43:27 +0000 |
17 | +++ django_configglue/management/commands/settings.py 2011-04-13 17:14:29 +0000 |
18 | @@ -106,7 +106,7 @@ |
19 | else: |
20 | # looking in django settings |
21 | for key in map(str.upper, keys): |
22 | - if key in settings.get_all_members(): |
23 | + if key in dir(settings): |
24 | msg = "setting %s last defined in %r" |
25 | output.append(msg % (key, os.path.realpath(location))) |
26 | else: |
27 | |
28 | === modified file 'django_configglue/schema.py' |
29 | --- django_configglue/schema.py 2011-02-19 23:14:11 +0000 |
30 | +++ django_configglue/schema.py 2011-04-13 17:14:29 +0000 |
31 | @@ -1,6 +1,7 @@ |
32 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
33 | # GNU Lesser General Public License version 3 (see the file LICENSE). |
34 | import logging |
35 | +from copy import deepcopy |
36 | |
37 | from configglue.pyschema.schema import ( |
38 | BoolConfigOption, |
39 | @@ -21,8 +22,20 @@ |
40 | gettext_noop = lambda s: s |
41 | |
42 | |
43 | +class UpperCaseDictConfigOption(DictConfigOption): |
44 | + """ A DictConfigOption with all upper-case keys. """ |
45 | + def parse(self, section, parser=None, raw=False): |
46 | + parsed = super(UpperCaseDictConfigOption, self).parse( |
47 | + section, parser, raw) |
48 | + result = {} |
49 | + for k, v in parsed.items(): |
50 | + result[k.upper()] = v |
51 | + return result |
52 | + |
53 | |
54 | class BaseDjangoSchema(Schema): |
55 | + version = '1.0.2 final' |
56 | + |
57 | # Sections |
58 | django = ConfigSection('django') |
59 | |
60 | @@ -256,6 +269,9 @@ |
61 | "secret-key hashing algorithms. Set this in your settings, or " |
62 | "Django will complain loudly") |
63 | |
64 | + django.jing_path = StringConfigOption(default='/usr/bin/jing', |
65 | + help="Path to the 'jing' executable -- needed to validate XMLFields") |
66 | + |
67 | django.default_file_storage = StringConfigOption( |
68 | default='django.core.files.storage.FileSystemStorage', |
69 | help="Default file storage mechanism that holds media") |
70 | @@ -452,23 +468,500 @@ |
71 | django.root_urlconf = StringConfigOption(default='urls') |
72 | |
73 | |
74 | -class Django102Schema(BaseDjangoSchema): |
75 | - version = '1.0.2' |
76 | - |
77 | - def __init__(self, *args, **kwargs): |
78 | - super(Django102Schema, self).__init__(*args, **kwargs) |
79 | - |
80 | - ################ |
81 | - # CORE # |
82 | - ################ |
83 | - |
84 | - self.django.jing_path = StringConfigOption(default='/usr/bin/jing', |
85 | - help="Path to the 'jing' executable -- needed to validate XMLFields") |
86 | - |
87 | - |
88 | class Django112Schema(BaseDjangoSchema): |
89 | version = '1.1.2' |
90 | |
91 | + # sections |
92 | + django = deepcopy(BaseDjangoSchema.django) |
93 | + |
94 | + ################ |
95 | + # CORE # |
96 | + ################ |
97 | + |
98 | + # update default value |
99 | + django.languages.default = ( |
100 | + ('ar', gettext_noop('Arabic')), |
101 | + ('bg', gettext_noop('Bulgarian')), |
102 | + ('bn', gettext_noop('Bengali')), |
103 | + ('bs', gettext_noop('Bosnian')), |
104 | + ('ca', gettext_noop('Catalan')), |
105 | + ('cs', gettext_noop('Czech')), |
106 | + ('cy', gettext_noop('Welsh')), |
107 | + ('da', gettext_noop('Danish')), |
108 | + ('de', gettext_noop('German')), |
109 | + ('el', gettext_noop('Greek')), |
110 | + ('en', gettext_noop('English')), |
111 | + ('es', gettext_noop('Spanish')), |
112 | + ('es-ar', gettext_noop('Argentinean Spanish')), |
113 | + ('et', gettext_noop('Estonian')), |
114 | + ('eu', gettext_noop('Basque')), |
115 | + ('fa', gettext_noop('Persian')), |
116 | + ('fi', gettext_noop('Finnish')), |
117 | + ('fr', gettext_noop('French')), |
118 | + ('fy-nl', gettext_noop('Frisian')), |
119 | + ('ga', gettext_noop('Irish')), |
120 | + ('gl', gettext_noop('Galician')), |
121 | + ('he', gettext_noop('Hebrew')), |
122 | + ('hi', gettext_noop('Hindi')), |
123 | + ('hr', gettext_noop('Croatian')), |
124 | + ('hu', gettext_noop('Hungarian')), |
125 | + ('is', gettext_noop('Icelandic')), |
126 | + ('it', gettext_noop('Italian')), |
127 | + ('ja', gettext_noop('Japanese')), |
128 | + ('ka', gettext_noop('Georgian')), |
129 | + ('km', gettext_noop('Khmer')), |
130 | + ('kn', gettext_noop('Kannada')), |
131 | + ('ko', gettext_noop('Korean')), |
132 | + ('lt', gettext_noop('Lithuanian')), |
133 | + ('lv', gettext_noop('Latvian')), |
134 | + ('mk', gettext_noop('Macedonian')), |
135 | + ('nl', gettext_noop('Dutch')), |
136 | + ('no', gettext_noop('Norwegian')), |
137 | + ('pl', gettext_noop('Polish')), |
138 | + ('pt', gettext_noop('Portuguese')), |
139 | + ('pt-br', gettext_noop('Brazilian Portuguese')), |
140 | + ('ro', gettext_noop('Romanian')), |
141 | + ('ru', gettext_noop('Russian')), |
142 | + ('sk', gettext_noop('Slovak')), |
143 | + ('sl', gettext_noop('Slovenian')), |
144 | + ('sq', gettext_noop('Albanian')), |
145 | + ('sr', gettext_noop('Serbian')), |
146 | + ('sr-latn', gettext_noop('Serbian Latin')), |
147 | + ('sv', gettext_noop('Swedish')), |
148 | + ('ta', gettext_noop('Tamil')), |
149 | + ('te', gettext_noop('Telugu')), |
150 | + ('th', gettext_noop('Thai')), |
151 | + ('tr', gettext_noop('Turkish')), |
152 | + ('uk', gettext_noop('Ukrainian')), |
153 | + ('zh-cn', gettext_noop('Simplified Chinese')), |
154 | + ('zh-tw', gettext_noop('Traditional Chinese')), |
155 | + ) |
156 | + |
157 | + |
158 | +class Django125Schema(Django112Schema): |
159 | + version = '1.2.5' |
160 | + |
161 | + # sections |
162 | + django = deepcopy(Django112Schema.django) |
163 | + |
164 | + ################ |
165 | + # CORE # |
166 | + ################ |
167 | + |
168 | + # update default value |
169 | + django.languages.default = [ |
170 | + ('ar', gettext_noop('Arabic')), |
171 | + ('bg', gettext_noop('Bulgarian')), |
172 | + ('bn', gettext_noop('Bengali')), |
173 | + ('bs', gettext_noop('Bosnian')), |
174 | + ('ca', gettext_noop('Catalan')), |
175 | + ('cs', gettext_noop('Czech')), |
176 | + ('cy', gettext_noop('Welsh')), |
177 | + ('da', gettext_noop('Danish')), |
178 | + ('de', gettext_noop('German')), |
179 | + ('el', gettext_noop('Greek')), |
180 | + ('en', gettext_noop('English')), |
181 | + ('en-gb', gettext_noop('British English')), |
182 | + ('es', gettext_noop('Spanish')), |
183 | + ('es-ar', gettext_noop('Argentinian Spanish')), |
184 | + ('et', gettext_noop('Estonian')), |
185 | + ('eu', gettext_noop('Basque')), |
186 | + ('fa', gettext_noop('Persian')), |
187 | + ('fi', gettext_noop('Finnish')), |
188 | + ('fr', gettext_noop('French')), |
189 | + ('fy-nl', gettext_noop('Frisian')), |
190 | + ('ga', gettext_noop('Irish')), |
191 | + ('gl', gettext_noop('Galician')), |
192 | + ('he', gettext_noop('Hebrew')), |
193 | + ('hi', gettext_noop('Hindi')), |
194 | + ('hr', gettext_noop('Croatian')), |
195 | + ('hu', gettext_noop('Hungarian')), |
196 | + ('id', gettext_noop('Indonesian')), |
197 | + ('is', gettext_noop('Icelandic')), |
198 | + ('it', gettext_noop('Italian')), |
199 | + ('ja', gettext_noop('Japanese')), |
200 | + ('ka', gettext_noop('Georgian')), |
201 | + ('km', gettext_noop('Khmer')), |
202 | + ('kn', gettext_noop('Kannada')), |
203 | + ('ko', gettext_noop('Korean')), |
204 | + ('lt', gettext_noop('Lithuanian')), |
205 | + ('lv', gettext_noop('Latvian')), |
206 | + ('mk', gettext_noop('Macedonian')), |
207 | + ('ml', gettext_noop('Malayalam')), |
208 | + ('mn', gettext_noop('Mongolian')), |
209 | + ('nl', gettext_noop('Dutch')), |
210 | + ('no', gettext_noop('Norwegian')), |
211 | + ('nb', gettext_noop('Norwegian Bokmal')), |
212 | + ('nn', gettext_noop('Norwegian Nynorsk')), |
213 | + ('pl', gettext_noop('Polish')), |
214 | + ('pt', gettext_noop('Portuguese')), |
215 | + ('pt-br', gettext_noop('Brazilian Portuguese')), |
216 | + ('ro', gettext_noop('Romanian')), |
217 | + ('ru', gettext_noop('Russian')), |
218 | + ('sk', gettext_noop('Slovak')), |
219 | + ('sl', gettext_noop('Slovenian')), |
220 | + ('sq', gettext_noop('Albanian')), |
221 | + ('sr', gettext_noop('Serbian')), |
222 | + ('sr-latn', gettext_noop('Serbian Latin')), |
223 | + ('sv', gettext_noop('Swedish')), |
224 | + ('ta', gettext_noop('Tamil')), |
225 | + ('te', gettext_noop('Telugu')), |
226 | + ('th', gettext_noop('Thai')), |
227 | + ('tr', gettext_noop('Turkish')), |
228 | + ('uk', gettext_noop('Ukrainian')), |
229 | + ('vi', gettext_noop('Vietnamese')), |
230 | + ('zh-cn', gettext_noop('Simplified Chinese')), |
231 | + ('zh-tw', gettext_noop('Traditional Chinese')), |
232 | + ] |
233 | + |
234 | + django.use_l10n = BoolConfigOption( |
235 | + default=True, |
236 | + help="If you set this to False, Django will not format dates, " |
237 | + "numbers and calendars according to the current locale") |
238 | + |
239 | + django.databases = DictConfigOption( |
240 | + item=UpperCaseDictConfigOption(spec={ |
241 | + 'engine': StringConfigOption(default='django.db.backends.'), |
242 | + 'name': StringConfigOption(), |
243 | + 'user': StringConfigOption(), |
244 | + 'password': StringConfigOption(), |
245 | + 'host': StringConfigOption(), |
246 | + 'port': StringConfigOption(), |
247 | + }), |
248 | + default={ |
249 | + 'default': { |
250 | + 'engine': 'django.db.backends.', |
251 | + 'name': '', |
252 | + 'user': '', |
253 | + 'password': '', |
254 | + 'host': '', |
255 | + 'port': '', |
256 | + } |
257 | + }) |
258 | + django.database_routers = LinesConfigOption( |
259 | + item=StringConfigOption(), |
260 | + help="Classes used to implement db routing behaviour") |
261 | + |
262 | + django.email_backend = StringConfigOption( |
263 | + default='django.core.mail.backends.smtp.EmailBackend', |
264 | + help="The email backend to use. For possible shortcuts see " |
265 | + "django.core.mail. The default is to use the SMTP backend. " |
266 | + "Third party backends can be specified by providing a Python " |
267 | + "path to a module that defines an EmailBackend class.") |
268 | + |
269 | + django.installed_apps.default = [ |
270 | + 'django.contrib.auth', |
271 | + 'django.contrib.contenttypes', |
272 | + 'django.contrib.sessions', |
273 | + 'django.contrib.sites', |
274 | + 'django.contrib.messages', |
275 | + ] |
276 | + |
277 | + django.template_loaders.default = [ |
278 | + 'django.template.loaders.filesystem.Loader', |
279 | + 'django.template.loaders.app_directories.Loader', |
280 | + ] |
281 | + |
282 | + django.template_context_processors.default = [ |
283 | + 'django.contrib.auth.context_processors.auth', |
284 | + 'django.core.context_processors.debug', |
285 | + 'django.core.context_processors.i18n', |
286 | + 'django.core.context_processors.media', |
287 | + 'django.contrib.messages.context_processors.messages', |
288 | + ] |
289 | + |
290 | + django.format_module_path = StringConfigOption( |
291 | + null=True, default=None, |
292 | + help="Python module path where user will place custom format " |
293 | + "definition. The directory where this setting is pointing " |
294 | + "should contain subdirectories named as the locales, " |
295 | + "containing a formats.py file") |
296 | + django.short_date_format = StringConfigOption( |
297 | + default='m/d/Y', |
298 | + help="Default short formatting for date objects") |
299 | + django.short_datetime_format = StringConfigOption( |
300 | + default='m/d/Y P', |
301 | + help="Default short formatting for datetime objects") |
302 | + django.date_input_formats = LinesConfigOption( |
303 | + item=StringConfigOption(), |
304 | + default=[ |
305 | + '%%Y-%%m-%%d', '%%m/%%d/%%Y', '%%m/%%d/%%y', # '2006-10-25', '10/25/2006', '10/25/06' |
306 | + '%%b %%d %%Y', '%%b %%d, %%Y', # 'Oct 25 2006', 'Oct 25, 2006' |
307 | + '%%d %%b %%Y', '%%d %%b, %%Y', # '25 Oct 2006', '25 Oct, 2006' |
308 | + '%%B %%d %%Y', '%%B %%d, %%Y', # 'October 25 2006', 'October 25, 2006' |
309 | + '%%d %%B %%Y', '%%d %%B, %%Y', # '25 October 2006', '25 October, 2006' |
310 | + ], |
311 | + help="Default formats to be used when parsing dates from input " |
312 | + "boxes, in order") |
313 | + django.time_input_formats = LinesConfigOption( |
314 | + item=StringConfigOption(), |
315 | + default=[ |
316 | + '%%H:%%M:%%S', # '14:30:59' |
317 | + '%%H:%%M', # '14:30' |
318 | + ], |
319 | + help="Default formats to be used when parsing times from input " |
320 | + "boxes, in order") |
321 | + django.datetime_input_formats = LinesConfigOption( |
322 | + item=StringConfigOption(), |
323 | + default=[ |
324 | + '%%Y-%%m-%%d %%H:%%M:%%S', # '2006-10-25 14:30:59' |
325 | + '%%Y-%%m-%%d %%H:%%M', # '2006-10-25 14:30' |
326 | + '%%Y-%%m-%%d', # '2006-10-25' |
327 | + '%%m/%%d/%%Y %%H:%%M:%%S', # '10/25/2006 14:30:59' |
328 | + '%%m/%%d/%%Y %%H:%%M', # '10/25/2006 14:30' |
329 | + '%%m/%%d/%%Y', # '10/25/2006' |
330 | + '%%m/%%d/%%y %%H:%%M:%%S', # '10/25/06 14:30:59' |
331 | + '%%m/%%d/%%y %%H:%%M', # '10/25/06 14:30' |
332 | + '%%m/%%d/%%y', # '10/25/06' |
333 | + ], |
334 | + help="Default formats to be used when parsing dates and times " |
335 | + "from input boxes, in order") |
336 | + |
337 | + django.first_day_of_week = IntConfigOption( |
338 | + default=0, |
339 | + help="First day of week, to be used on calendars. 0 means Sunday, " |
340 | + "1 means Monday...") |
341 | + django.decimal_separator = StringConfigOption( |
342 | + default='.', |
343 | + help="Decimal separator symbol") |
344 | + django.use_thousand_separator = BoolConfigOption( |
345 | + default=False, |
346 | + help="Boolean that sets whether to add thousand separator when " |
347 | + "formatting numbers") |
348 | + django.number_grouping = IntConfigOption( |
349 | + default=0, |
350 | + help="Number of digits that will be together, when splitting them " |
351 | + "by THOUSAND_SEPARATOR. 0 means no grouping, 3 means " |
352 | + "splitting by thousands...") |
353 | + django.thousand_separator = StringConfigOption( |
354 | + default=',', |
355 | + help="Thousand separator symbol") |
356 | + |
357 | + ############## |
358 | + # MIDDLEWARE # |
359 | + ############## |
360 | + |
361 | + django.middleware_classes.default = [ |
362 | + 'django.middleware.common.CommonMiddleware', |
363 | + 'django.contrib.sessions.middleware.SessionMiddleware', |
364 | + 'django.middleware.csrf.CsrfViewMiddleware', |
365 | + 'django.contrib.auth.middleware.AuthenticationMiddleware', |
366 | + 'django.contrib.messages.middleware.MessageMiddleware', |
367 | + ] |
368 | + |
369 | + ######## |
370 | + # CSRF # |
371 | + ######## |
372 | + |
373 | + django.csrf_failure_view = StringConfigOption( |
374 | + default='django.views.csrf.csrf_failure', |
375 | + help="Dotted path to callable to be used as view when a request " |
376 | + "is rejected by the CSRF middleware") |
377 | + django.csrf_cookie_name = StringConfigOption( |
378 | + default='csrftoken', |
379 | + help="Name for CSRF cookie") |
380 | + django.csrf_cookie_domain = StringConfigOption( |
381 | + null=True, |
382 | + help="Domain for CSRF cookie") |
383 | + |
384 | + ############ |
385 | + # MESSAGES # |
386 | + ############ |
387 | + |
388 | + django.message_storage = StringConfigOption( |
389 | + default='django.contrib.messages.storage.user_messages.' |
390 | + 'LegacyFallbackStorage', |
391 | + help="Class to be used as messages backend") |
392 | + |
393 | + ########### |
394 | + # TESTING # |
395 | + ########### |
396 | + |
397 | + django.test_runner.default = ( |
398 | + 'django.test.simple.DjangoTestSuiteRunner') |
399 | + django.test_runner.help = ( |
400 | + "The name of the class to use to run the test suite") |
401 | + |
402 | + |
403 | +class Django13Schema(Django125Schema): |
404 | + version = '1.3' |
405 | + |
406 | + # sections |
407 | + django = deepcopy(Django125Schema.django) |
408 | + |
409 | + ################ |
410 | + # CORE # |
411 | + ################ |
412 | + |
413 | + # update default value |
414 | + django.languages.default = [ |
415 | + ('ar', gettext_noop('Arabic')), |
416 | + ('az', gettext_noop('Azerbaijani')), |
417 | + ('bg', gettext_noop('Bulgarian')), |
418 | + ('bn', gettext_noop('Bengali')), |
419 | + ('bs', gettext_noop('Bosnian')), |
420 | + ('ca', gettext_noop('Catalan')), |
421 | + ('cs', gettext_noop('Czech')), |
422 | + ('cy', gettext_noop('Welsh')), |
423 | + ('da', gettext_noop('Danish')), |
424 | + ('de', gettext_noop('German')), |
425 | + ('el', gettext_noop('Greek')), |
426 | + ('en', gettext_noop('English')), |
427 | + ('en-gb', gettext_noop('British English')), |
428 | + ('es', gettext_noop('Spanish')), |
429 | + ('es-ar', gettext_noop('Argentinian Spanish')), |
430 | + ('es-mx', gettext_noop('Mexican Spanish')), |
431 | + ('es-ni', gettext_noop('Nicaraguan Spanish')), |
432 | + ('et', gettext_noop('Estonian')), |
433 | + ('eu', gettext_noop('Basque')), |
434 | + ('fa', gettext_noop('Persian')), |
435 | + ('fi', gettext_noop('Finnish')), |
436 | + ('fr', gettext_noop('French')), |
437 | + ('fy-nl', gettext_noop('Frisian')), |
438 | + ('ga', gettext_noop('Irish')), |
439 | + ('gl', gettext_noop('Galician')), |
440 | + ('he', gettext_noop('Hebrew')), |
441 | + ('hi', gettext_noop('Hindi')), |
442 | + ('hr', gettext_noop('Croatian')), |
443 | + ('hu', gettext_noop('Hungarian')), |
444 | + ('id', gettext_noop('Indonesian')), |
445 | + ('is', gettext_noop('Icelandic')), |
446 | + ('it', gettext_noop('Italian')), |
447 | + ('ja', gettext_noop('Japanese')), |
448 | + ('ka', gettext_noop('Georgian')), |
449 | + ('km', gettext_noop('Khmer')), |
450 | + ('kn', gettext_noop('Kannada')), |
451 | + ('ko', gettext_noop('Korean')), |
452 | + ('lt', gettext_noop('Lithuanian')), |
453 | + ('lv', gettext_noop('Latvian')), |
454 | + ('mk', gettext_noop('Macedonian')), |
455 | + ('ml', gettext_noop('Malayalam')), |
456 | + ('mn', gettext_noop('Mongolian')), |
457 | + ('nl', gettext_noop('Dutch')), |
458 | + ('no', gettext_noop('Norwegian')), |
459 | + ('nb', gettext_noop('Norwegian Bokmal')), |
460 | + ('nn', gettext_noop('Norwegian Nynorsk')), |
461 | + ('pa', gettext_noop('Punjabi')), |
462 | + ('pl', gettext_noop('Polish')), |
463 | + ('pt', gettext_noop('Portuguese')), |
464 | + ('pt-br', gettext_noop('Brazilian Portuguese')), |
465 | + ('ro', gettext_noop('Romanian')), |
466 | + ('ru', gettext_noop('Russian')), |
467 | + ('sk', gettext_noop('Slovak')), |
468 | + ('sl', gettext_noop('Slovenian')), |
469 | + ('sq', gettext_noop('Albanian')), |
470 | + ('sr', gettext_noop('Serbian')), |
471 | + ('sr-latn', gettext_noop('Serbian Latin')), |
472 | + ('sv', gettext_noop('Swedish')), |
473 | + ('ta', gettext_noop('Tamil')), |
474 | + ('te', gettext_noop('Telugu')), |
475 | + ('th', gettext_noop('Thai')), |
476 | + ('tr', gettext_noop('Turkish')), |
477 | + ('uk', gettext_noop('Ukrainian')), |
478 | + ('ur', gettext_noop('Urdu')), |
479 | + ('vi', gettext_noop('Vietnamese')), |
480 | + ('zh-cn', gettext_noop('Simplified Chinese')), |
481 | + ('zh-tw', gettext_noop('Traditional Chinese')), |
482 | + ] |
483 | + |
484 | + django.template_context_processors.default = [ |
485 | + 'django.contrib.auth.context_processors.auth', |
486 | + 'django.core.context_processors.debug', |
487 | + 'django.core.context_processors.i18n', |
488 | + 'django.core.context_processors.media', |
489 | + 'django.core.context_processors.static', |
490 | + 'django.contrib.messages.context_processors.messages', |
491 | + ] |
492 | + |
493 | + django.static_root = StringConfigOption( |
494 | + default='', |
495 | + help='Absolute path to the directory that holds static files.') |
496 | + |
497 | + django.static_url = StringConfigOption( |
498 | + null=True, default=None, |
499 | + help='URL that handles the static files served from STATIC_ROOT.') |
500 | + |
501 | + ############ |
502 | + # SESSIONS # |
503 | + ############ |
504 | + |
505 | + django.session_cookie_httponly = BoolConfigOption( |
506 | + default=False, |
507 | + help='Whether to use the non-RFC standard htt pOnly flag (IE, FF3+, others)') |
508 | + |
509 | + ######### |
510 | + # CACHE # |
511 | + ######### |
512 | + |
513 | + # remove obsoleted setting |
514 | + del django.cache_backend |
515 | + |
516 | + django.caches = DictConfigOption() |
517 | + django.cache_middleware_alias = StringConfigOption(default='default') |
518 | + |
519 | + ############ |
520 | + # COMMENTS # |
521 | + ############ |
522 | + |
523 | + django.profanities_list.default = () |
524 | + |
525 | + ########### |
526 | + # LOGGING # |
527 | + ########### |
528 | + |
529 | + django.logging_config = StringConfigOption( |
530 | + default='django.utils.log.dictConfig', |
531 | + help='The callable to use to configure logging') |
532 | + django.logging = DictConfigOption( |
533 | + spec={ |
534 | + 'version': IntConfigOption(default=1), |
535 | + 'disable_existing_loggers': BoolConfigOption(default=False), |
536 | + 'handlers': DictConfigOption( |
537 | + spec={ |
538 | + 'mail_admins': DictConfigOption( |
539 | + spec={ |
540 | + 'level': StringConfigOption(default='ERROR'), |
541 | + 'class': StringConfigOption( |
542 | + default='django.utils.log.AdminEmailHandler'), |
543 | + }), |
544 | + }), |
545 | + 'loggers': DictConfigOption( |
546 | + spec={ |
547 | + 'django.request': DictConfigOption( |
548 | + spec={ |
549 | + 'handlers': LinesConfigOption( |
550 | + item=StringConfigOption(), |
551 | + default=['mail_admins']), |
552 | + 'level': StringConfigOption(default='ERROR'), |
553 | + 'propagate': BoolConfigOption(default=False), |
554 | + }), |
555 | + }), |
556 | + }, |
557 | + help='The default logging configuration. This sends an email to the ' |
558 | + 'site admins on every HTTP 500 error. All other records are sent ' |
559 | + 'to the bit bucket.') |
560 | + |
561 | + ############### |
562 | + # STATICFILES # |
563 | + ############### |
564 | + |
565 | + django.staticfiles_dirs = LinesConfigOption( |
566 | + item=StringConfigOption(), |
567 | + help='A list of locations of additional static files') |
568 | + django.staticfiles_storage = StringConfigOption( |
569 | + default='django.contrib.staticfiles.storage.StaticFilesStorage', |
570 | + help='The default file storage backend used during the build process') |
571 | + django.staticfiles_finders = LinesConfigOption( |
572 | + item=StringConfigOption(), |
573 | + default=[ |
574 | + 'django.contrib.staticfiles.finders.FileSystemFinder', |
575 | + 'django.contrib.staticfiles.finders.AppDirectoriesFinder', |
576 | + ], |
577 | + help='List of finder classes that know how to find static files in ' |
578 | + 'various locations.') |
579 | + |
580 | + django.admin_media_prefix.default = '/static/admin/' |
581 | + |
582 | |
583 | class DjangoSchemaFactory(object): |
584 | def __init__(self): |
585 | @@ -506,8 +999,9 @@ |
586 | |
587 | |
588 | schemas = DjangoSchemaFactory() |
589 | -schemas.register(Django102Schema) |
590 | +schemas.register(BaseDjangoSchema, '1.0.2 final') |
591 | +schemas.register(BaseDjangoSchema, '1.0.4') |
592 | schemas.register(Django112Schema) |
593 | -# also register the same schema for lucid's django version (which is exported |
594 | -# as 1.1.1 but is essentially 1.1.2 |
595 | -schemas.register(Django112Schema, '1.1.1') |
596 | +schemas.register(Django112Schema, '1.1.4') |
597 | +schemas.register(Django125Schema) |
598 | +schemas.register(Django13Schema) |
599 | |
600 | === modified file 'django_configglue/tests/helpers.py' |
601 | --- django_configglue/tests/helpers.py 2011-01-17 15:32:29 +0000 |
602 | +++ django_configglue/tests/helpers.py 2011-04-13 17:14:29 +0000 |
603 | @@ -3,6 +3,7 @@ |
604 | |
605 | import os |
606 | import sys |
607 | +import textwrap |
608 | from StringIO import StringIO |
609 | |
610 | import django |
611 | @@ -15,13 +16,27 @@ |
612 | COMMAND = '' |
613 | |
614 | def setUp(self): |
615 | - config = """ |
616 | -[django] |
617 | -database_engine = sqlite3 |
618 | -database_name = :memory: |
619 | -installed_apps = django_configglue |
620 | -time_zone = Europe/London |
621 | -""" |
622 | + config = textwrap.dedent(""" |
623 | + [django] |
624 | + database_engine = sqlite3 |
625 | + database_name = :memory: |
626 | + installed_apps = django_configglue |
627 | + time_zone = Europe/London |
628 | + """) |
629 | + |
630 | + if django.VERSION[:2] > (1, 1): |
631 | + # since 1.2 use multi database settings format |
632 | + config += textwrap.dedent(""" |
633 | + databases = databases |
634 | + |
635 | + [databases] |
636 | + default = db_default |
637 | + |
638 | + [db_default] |
639 | + engine = sqlite3 |
640 | + name = :memory: |
641 | + """) |
642 | + |
643 | self.set_config(config) |
644 | self._DJANGO_SETTINGS_MODULE = self.load_settings() |
645 | |
646 | @@ -39,10 +54,13 @@ |
647 | |
648 | @property |
649 | def wrapped_settings(self): |
650 | - if django.VERSION[:2] < (1, 1): |
651 | - wrapped = '_target' |
652 | - else: |
653 | + wrapped = '_target' |
654 | + if django.VERSION[:3] > (1, 0, 2): |
655 | wrapped = '_wrapped' |
656 | + # make sure the wrapped object is not None |
657 | + # by just querying it for a setting |
658 | + getattr(settings, 'DEBUG', False) |
659 | + assert(getattr(settings, wrapped) != None) |
660 | return wrapped |
661 | |
662 | def load_settings(self, module='django_configglue.tests.settings'): |
663 | @@ -51,9 +69,8 @@ |
664 | if old_module in sys.modules: |
665 | del sys.modules[old_module] |
666 | # keep runtime settings |
667 | - if django.VERSION[:2] < (1, 1): |
668 | - extra_settings = {} |
669 | - else: |
670 | + extra_settings = {} |
671 | + if django.VERSION[:2] == (1, 1): |
672 | extra_settings = { |
673 | 'DATABASE_NAME': settings.DATABASE_NAME, |
674 | 'DATABASE_SUPPORTS_TRANSACTIONS': getattr( |
675 | |
676 | === modified file 'django_configglue/tests/settings.py' |
677 | --- django_configglue/tests/settings.py 2011-01-17 15:32:29 +0000 |
678 | +++ django_configglue/tests/settings.py 2011-04-13 17:14:29 +0000 |
679 | @@ -6,6 +6,9 @@ |
680 | from django_configglue.schema import schemas |
681 | |
682 | |
683 | -DjangoSchema = schemas.get(django.get_version()) |
684 | -configglue(DjangoSchema, ['main.cfg', 'test.cfg'], __name__) |
685 | +DjangoSchema = schemas.get(django.get_version(), strict=False) |
686 | +main_cfg = 'main.cfg' |
687 | +if DjangoSchema.version >= '1.2': |
688 | + main_cfg = 'main-12.cfg' |
689 | +configglue(DjangoSchema, [main_cfg, 'test.cfg'], __name__) |
690 | |
691 | |
692 | === modified file 'django_configglue/tests/test_configglue.py' |
693 | --- django_configglue/tests/test_configglue.py 2011-02-19 23:14:11 +0000 |
694 | +++ django_configglue/tests/test_configglue.py 2011-04-13 17:14:29 +0000 |
695 | @@ -2,9 +2,11 @@ |
696 | # Copyright 2010 Canonical Ltd. This software is licensed under the |
697 | # GNU Lesser General Public License version 3 (see the file LICENSE). |
698 | |
699 | +import textwrap |
700 | from cStringIO import StringIO |
701 | from unittest import TestCase |
702 | |
703 | +import django |
704 | from configglue.pyschema.schema import ( |
705 | DictConfigOption, |
706 | IntConfigOption, |
707 | @@ -26,10 +28,10 @@ |
708 | update_settings, |
709 | ) |
710 | from django_configglue.schema import ( |
711 | - schemas, |
712 | BaseDjangoSchema, |
713 | - Django102Schema, |
714 | DjangoSchemaFactory, |
715 | + UpperCaseDictConfigOption, |
716 | + schemas, |
717 | ) |
718 | from django_configglue.tests.helpers import ConfigGlueDjangoCommandTestCase |
719 | |
720 | @@ -38,8 +40,9 @@ |
721 | def test_get_django_settings(self): |
722 | class MySchema(Schema): |
723 | foo = IntConfigOption() |
724 | - bar = DictConfigOption({'baz': IntConfigOption(), |
725 | - 'BAZ': IntConfigOption()}) |
726 | + bar = DictConfigOption( |
727 | + spec={'baz': IntConfigOption(), |
728 | + 'BAZ': IntConfigOption()}) |
729 | |
730 | expected = {'FOO': 0, 'BAR': {'baz': 0, 'BAZ': 0}} |
731 | |
732 | @@ -76,7 +79,7 @@ |
733 | |
734 | def test_schemafactory_get(self): |
735 | # test get valid version |
736 | - self.assertEqual(schemas.get('1.0.2'), Django102Schema) |
737 | + self.assertEqual(schemas.get('1.0.2 final'), BaseDjangoSchema) |
738 | |
739 | # test get invalid version |
740 | self.assertRaises(ValueError, schemas.get, '1.1') |
741 | @@ -85,64 +88,63 @@ |
742 | def test_schemafactory_get_nonexisting_too_old(self, mock_logging): |
743 | schema = schemas.get('0.96', strict=False) |
744 | |
745 | - django_102 = schemas.get('1.0.2') |
746 | + django_102 = schemas.get('1.0.2 final') |
747 | self.assertEqual(schema, django_102) |
748 | self.assertRaises(ValueError, schemas.get, '0.96') |
749 | |
750 | self.assertEqual(mock_logging.warn.call_args_list[0][0][0], |
751 | "No schema registered for version '0.96'") |
752 | self.assertEqual(mock_logging.warn.call_args_list[1][0][0], |
753 | - "Falling back to schema for version '1.0.2'") |
754 | + "Falling back to schema for version '1.0.2 final'") |
755 | |
756 | @patch('django_configglue.schema.logging') |
757 | def test_schemafactory_get_nonexisting(self, mock_logging): |
758 | schema = schemas.get('1.0.3', strict=False) |
759 | |
760 | - django_102 = schemas.get('1.0.2') |
761 | + django_102 = schemas.get('1.0.2 final') |
762 | self.assertEqual(schema, django_102) |
763 | self.assertRaises(ValueError, schemas.get, '1.0.3') |
764 | |
765 | self.assertEqual(mock_logging.warn.call_args_list[0][0][0], |
766 | "No schema registered for version '1.0.3'") |
767 | self.assertEqual(mock_logging.warn.call_args_list[1][0][0], |
768 | - "Falling back to schema for version '1.0.2'") |
769 | + "Falling back to schema for version '1.0.2 final'") |
770 | |
771 | @patch('django_configglue.schema.logging') |
772 | def test_schemafactory_get_nonexisting_too_new(self, mock_logging): |
773 | schema = schemas.get('1.2.0', strict=False) |
774 | |
775 | - django_112 = schemas.get('1.1.2') |
776 | + django_112 = schemas.get('1.1.4') |
777 | self.assertEqual(schema, django_112) |
778 | self.assertRaises(ValueError, schemas.get, '1.2.0') |
779 | |
780 | self.assertEqual(mock_logging.warn.call_args_list[0][0][0], |
781 | "No schema registered for version '1.2.0'") |
782 | self.assertEqual(mock_logging.warn.call_args_list[1][0][0], |
783 | - "Falling back to schema for version '1.1.2'") |
784 | + "Falling back to schema for version '1.1.4'") |
785 | |
786 | @patch('django_configglue.schema.logging') |
787 | def test_schemafactory_get_no_versions_registered(self, mock_logging): |
788 | schemas = DjangoSchemaFactory() |
789 | try: |
790 | - schemas.get('1.0.2', strict=False) |
791 | + schemas.get('1.0.2 final', strict=False) |
792 | except ValueError, e: |
793 | self.assertEqual(str(e), "No schemas registered") |
794 | else: |
795 | self.fail("ValueError not raised") |
796 | |
797 | mock_logging.warn.assert_called_with( |
798 | - "No schema registered for version '1.0.2'") |
799 | + "No schema registered for version '1.0.2 final'") |
800 | |
801 | def test_schema_versions(self): |
802 | - django_102 = schemas.get('1.0.2')() |
803 | + django_102 = schemas.get('1.0.2 final')() |
804 | django_112 = schemas.get('1.1.2')() |
805 | - self.assertEqual(django_102.version, '1.0.2') |
806 | - self.assertTrue(hasattr(django_102.django, 'jing_path')) |
807 | + self.assertEqual(django_102.version, '1.0.2 final') |
808 | self.assertEqual(django_112.version, '1.1.2') |
809 | - self.assertFalse(hasattr(django_112.django, 'jing_path')) |
810 | + self.assertFalse(django_102 is django_112) |
811 | |
812 | def test_register_without_version(self): |
813 | - class MySchema(BaseDjangoSchema): |
814 | + class MySchema(Schema): |
815 | pass |
816 | |
817 | schemas = DjangoSchemaFactory() |
818 | @@ -150,12 +152,13 @@ |
819 | |
820 | def test_configglue(self): |
821 | target = {} |
822 | - configglue(BaseDjangoSchema, [], target) |
823 | + schema = schemas.get(django.get_version(), strict=False) |
824 | + configglue(schema, [], target) |
825 | # target is consistent with django's settings module |
826 | # except for a few keys |
827 | shared_key = lambda x: (not x.startswith('__') and x.upper() == x and |
828 | x not in ('DATABASE_SUPPORTS_TRANSACTIONS', 'SETTINGS_MODULE')) |
829 | - expected_keys = set(filter(shared_key, settings.get_all_members())) |
830 | + expected_keys = set(filter(shared_key, dir(settings))) |
831 | target_keys = set(filter(shared_key, target.keys())) |
832 | |
833 | self.assertEqual(expected_keys, target_keys) |
834 | @@ -245,3 +248,22 @@ |
835 | self.execute() |
836 | self.assertTrue('Show settings attributes' in self.capture['stdout']) |
837 | |
838 | + |
839 | +class UpperCaseDictConfigOptionTestCase(TestCase): |
840 | + def test_parse(self): |
841 | + class MySchema(Schema): |
842 | + foo = UpperCaseDictConfigOption() |
843 | + config = StringIO(textwrap.dedent(""" |
844 | + [__main__] |
845 | + foo = mydict |
846 | + [mydict] |
847 | + bar = 42 |
848 | + """)) |
849 | + |
850 | + schema = MySchema() |
851 | + parser = SchemaConfigParser(schema) |
852 | + parser.readfp(config) |
853 | + result = schema.foo.parse('mydict', parser) |
854 | + |
855 | + self.assertEqual(result, {'BAR': '42'}) |
856 | + |
857 | |
858 | === modified file 'django_configglue/tests/test_settings.py' |
859 | --- django_configglue/tests/test_settings.py 2011-01-17 16:01:13 +0000 |
860 | +++ django_configglue/tests/test_settings.py 2011-04-13 17:14:29 +0000 |
861 | @@ -36,8 +36,11 @@ |
862 | "SETTINGS_MODULE = 'django_configglue.tests.settings'", |
863 | "SETTINGS_ENCODING = '%s'" % SETTINGS_ENCODING, |
864 | ] |
865 | - if django.VERSION[:2] >= (1, 1): |
866 | + django_version = django.VERSION[:2] |
867 | + if django_version == (1, 1): |
868 | expected_values.append("DATABASE_SUPPORTS_TRANSACTIONS = True") |
869 | + if django_version >= (1, 1): |
870 | + expected_values.append("JING_PATH = '/usr/bin/jing'") |
871 | self.call_command(show_current=True) |
872 | output_lines = self.capture['stdout'].strip().split('\n') |
873 | self.assertEqual(set(expected_values), set(output_lines)) |
874 | @@ -94,16 +97,15 @@ |
875 | wrapped.__CONFIGGLUE_PARSER__ = old_CONFIGGLUE_PARSER |
876 | |
877 | def test_wrapped_settings(self): |
878 | - old_VERSION = django.VERSION |
879 | - |
880 | - try: |
881 | - django.VERSION = (1, 0, 2) |
882 | - self.assertEqual(self.wrapped_settings, '_target') |
883 | - |
884 | - django.VERSION = (1, 1, 2) |
885 | - self.assertEqual(self.wrapped_settings, '_wrapped') |
886 | - finally: |
887 | - django.VERSION = old_VERSION |
888 | + # the settings object has a _target attribute |
889 | + # this is true for versions of django <= 1.0.2 |
890 | + expected = '_target' |
891 | + if django.VERSION[:3] > (1, 0, 2): |
892 | + # the settings object has a _wrapped attribute |
893 | + # this is true for versions of django > 1.0.2 |
894 | + expected = '_wrapped' |
895 | + |
896 | + self.assertEqual(self.wrapped_settings, expected) |
897 | |
898 | |
899 | class ValidateCommandTestCase(ConfigGlueDjangoCommandTestCase): |
900 | |
901 | === modified file 'django_configglue/utils.py' |
902 | --- django_configglue/utils.py 2011-01-17 15:32:29 +0000 |
903 | +++ django_configglue/utils.py 2011-04-13 17:14:29 +0000 |
904 | @@ -55,3 +55,4 @@ |
905 | scp = SchemaConfigParser(schema_class()) |
906 | scp.read(configs) |
907 | update_settings(scp, target) |
908 | + return scp |
909 | |
910 | === added file 'testproject/main-12.cfg' |
911 | --- testproject/main-12.cfg 1970-01-01 00:00:00 +0000 |
912 | +++ testproject/main-12.cfg 2011-04-13 17:14:29 +0000 |
913 | @@ -0,0 +1,12 @@ |
914 | +[django] |
915 | +database_engine = sqlite3 |
916 | +database_name = :memory: |
917 | +installed_apps = django_configglue |
918 | +databases = databases |
919 | + |
920 | +[databases] |
921 | +default = db_default |
922 | + |
923 | +[db_default] |
924 | +engine = sqlite3 |
925 | +name = :memory: |
926 | |
927 | === modified file 'testproject/main.cfg' |
928 | --- testproject/main.cfg 2010-08-06 19:27:35 +0000 |
929 | +++ testproject/main.cfg 2011-04-13 17:14:29 +0000 |
930 | @@ -1,4 +1,3 @@ |
931 | - |
932 | [django] |
933 | database_engine = sqlite3 |
934 | database_name = :memory: |
935 | |
936 | === modified file 'testproject/testrunner.py' |
937 | --- testproject/testrunner.py 2010-10-13 16:11:56 +0000 |
938 | +++ testproject/testrunner.py 2011-04-13 17:14:29 +0000 |
939 | @@ -11,10 +11,8 @@ |
940 | |
941 | os.environ['DJANGO_SETTINGS_MODULE'] = 'testproject.settings' |
942 | |
943 | - from django.conf import settings |
944 | - from django.test.utils import get_runner |
945 | + from django.core.management import call_command |
946 | |
947 | - test_runner = get_runner(settings) |
948 | - failures = test_runner(['django_configglue'], verbosity=1, interactive=True) |
949 | - sys.exit(failures) |
950 | + call_command('test', 'django_configglue') |
951 | + sys.exit(0) |
952 | |
953 | |
954 | === added file 'tox' |
955 | --- tox 1970-01-01 00:00:00 +0000 |
956 | +++ tox 2011-04-13 17:14:29 +0000 |
957 | @@ -0,0 +1,6 @@ |
958 | +#!/usr/bin/env python |
959 | +import urllib |
960 | +url = "https://pytox.googlecode.com/hg/toxbootstrap.py" |
961 | +d = dict(__file__='toxbootstrap.py') |
962 | +exec urllib.urlopen(url).read() in d |
963 | +d['cmdline'](['--recreate']) |
964 | \ No newline at end of file |
965 | |
966 | === added file 'tox.ini' |
967 | --- tox.ini 1970-01-01 00:00:00 +0000 |
968 | +++ tox.ini 2011-04-13 17:14:29 +0000 |
969 | @@ -0,0 +1,47 @@ |
970 | +[tox] |
971 | +envlist = |
972 | + py26-django102, |
973 | + py26-django104, |
974 | + py26-django112, |
975 | + py26-django114, |
976 | + py26-django125, |
977 | + py26-django13 |
978 | + |
979 | +[testenv] |
980 | +commands = python setup.py test |
981 | + |
982 | +[testenv:py26-django102] |
983 | +deps = |
984 | + configglue |
985 | + mock |
986 | + django==1.0.2-final |
987 | + |
988 | +[testenv:py26-django104] |
989 | +deps = |
990 | + configglue |
991 | + mock |
992 | + django==1.0.4 |
993 | + |
994 | +[testenv:py26-django112] |
995 | +deps = |
996 | + configglue |
997 | + mock |
998 | + django==1.1.2 |
999 | + |
1000 | +[testenv:py26-django114] |
1001 | +deps = |
1002 | + configglue |
1003 | + mock |
1004 | + django==1.1.4 |
1005 | + |
1006 | +[testenv:py26-django125] |
1007 | +deps = |
1008 | + configglue |
1009 | + mock |
1010 | + django==1.2.5 |
1011 | + |
1012 | +[testenv:py26-django13] |
1013 | +deps = |
1014 | + configglue |
1015 | + mock |
1016 | + django==1.3 |
You can move common dependencies for each environment to [testenv] section. Like
[testenv]
deps = configglue
mock