Merge lp:~ricardokirkner/django-configglue/tox into lp:django-configglue

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
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 :

You can move common dependencies for each environment to [testenv] section. Like

[testenv]
deps = configglue
       mock

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

Subscribers

People subscribed via source and target branches

to all changes: