A => .hgignore +5 -0
@@ 0,0 1,5 @@
+syntax:glob
+.svn
+.hgsvn
+.*.swp
+**.pyc
A => LICENSE +32 -0
@@ 0,0 1,32 @@
+Copyright (c) 2010, Peter Sanchez <petersanchez@gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or
+without modification, are permitted provided that the
+following conditions are met:
+
+ * Redistributions of source code must retain the above
+ copyright notice, this list of conditions and the
+ following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+ * Neither the name of Peter Sanchez nor the names of its
+ contributors may be used to endorse or promote products
+ derived from this software without specific prior written
+ permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
A => README.txt +126 -0
@@ 0,0 1,126 @@
+django-easyconfig
+------------------
+
+This app will make it easy to customize external Django apps
+that use it.
+
+It takes an approach very similar to the django.contrib.comments
+framework. It makes it easy to use custom forms, values, etc.
+
+Quick example...
+
+Say you have an open source Django app that lets you upload a
+Photo and some metadata to that photo. To be able to customize
+that form, the project owners would have to hack the app's
+source to fit their needs (class names, etc.) or you have to
+make your app customizable. That's where django-easyconfig
+comes in...
+
+
+Install
+-------
+
+Basic Install:
+
+ $ python setup.py build
+ $ sudo python setup.py install
+
+Alternative Install (Manually):
+
+Place webutils directory in your Python path. Either in your Python
+installs site-packages directory or set your $PYTHONPATH environment
+variable to include a directory where the webutils directory lives.
+
+
+Use
+---
+
+* XXX * These are not great docs. I'll work on updating this soon!
+
+You must create a "Config" object in your app and use that to fetch
+any object or value you want to be able to have customized.
+
+Here is a basic example.
+
+### yourapp/__init__.py
+
+from django.contrib.auth.forms import AuthenticationForm
+from yourapp.forms import PasswordChangeForm
+from easyconfig import EasyConfig
+
+
+class Config(object):
+ ''' Base config class to easily pass forms, etc. to
+ yourapp views.
+ '''
+ # Use the dotted Python path to this class
+ config = EasyConfig('yourapp.Config', 'YOURAPP_CONFIG')
+
+ def get_login_form(self):
+ return self.config.get_object('get_login_form', AuthenticationForm)
+
+ def get_password_change_form(self):
+ return self.config.get_object('get_password_change_form', PasswordChangeForm)
+
+
+Now, you just need to use your yourapp.Config class any time you need
+to fetch one of these objects for use.
+
+Here's how it could be used in a urls.py file
+
+### urls.py
+
+from yourapp import Config
+from django.conf.urls.defaults import *
+
+
+config = Config()
+
+urlpatterns = patterns('yourapp.views',
+ url(r'^login/$',
+ 'login', {
+ 'template_name': 'yourapp/login.html',
+ 'authentication_form': config.get_login_form(),
+ }, name='yourapp-login'),
+ url(r'^passwd_change/$',
+ 'passwd_change', {
+ 'template_name': 'yourapp/passwd_change.html',
+ 'passwd_change_form': config.get_password_change_form(),
+ }, name='yourapp-passwd-change'),
+)
+
+Now, anybody using your app in their own project can easily change the
+login and password change forms to whatever form they want. Here is how
+they would do so in their own project.
+
+
+### settings.py
+
+# Dotted python path to their own CustomConfig class
+YOURAPP_CONFIG = 'myproject.myapp.CustomConfig'
+
+
+### myproject/myapp/__init__.py
+
+from myproject.myapp.forms import AuthForm, ChangeForm
+
+
+class CustomConfig(object):
+ ''' Customize the forms!
+ '''
+ def get_login_form(self):
+ return AuthForm
+
+ def get_password_change_form(self):
+ return ChangeForm
+
+
+That's it. Easy right? :)
+
+
+Copyright & Warranty
+--------------------
+All documentation, libraries, and sample code are
+Copyright 2010 Peter Sanchez <petersanchez@gmail.com>. The library and
+sample code are made available to you under the terms of the BSD license
+which is contained in the included file, BSD-LICENSE.
A => easyconfig/__init__.py +52 -0
@@ 0,0 1,52 @@
+from django.conf import settings
+from django.core.exceptions import ImproperlyConfigured
+from django.utils.importlib import import_module
+
+
+__version__ = '0.1'
+
+
+class EasyConfig(object):
+ def __init__(self, default_module, setting_name):
+ self.default_module = default_module
+ self.setting_name = setting_name
+
+ def _get_config(self):
+ ''' Get the config as defined in the settings
+ '''
+ config = self._get_config_name()
+ try:
+ package = import_module(config)
+ except ImportError:
+ path = '.'.join(config.split('.')[:-1])
+ pkg = config.split('.')[-1]
+ try:
+ tmp_package = import_module(path, package=pkg)
+ package = getattr(tmp_package, pkg)
+ except (ImportError, AttributeError):
+ raise ImproperlyConfigured(
+ 'The %s setting refers to a non-existing package.' % \
+ self.setting_name
+ )
+
+ if callable(package):
+ package = package()
+ return package
+
+ def _get_config_name(self):
+ ''' Returns the name of the support config (either the setting value,
+ if it exists, or the default).
+ '''
+ return getattr(settings, self.setting_name, self.default_module)
+
+
+ def get_object(self, method, default_obj):
+ ''' Check that the support config is custom, and if so, that the
+ right methods exist. If not, return the default_obj
+ '''
+ if self._get_config_name() != self.default_module:
+ config = self._get_config()
+ if hasattr(config, method):
+ return getattr(config, method)()
+
+ return default_obj
A => setup.py +51 -0
@@ 0,0 1,51 @@
+import os
+from distutils.core import setup
+
+
+project_name = 'easyconfig'
+long_description = open('README.txt').read()
+
+# Idea from django-registration setup.py
+packages, data_files = [], []
+root_dir = os.path.dirname(__file__)
+if root_dir:
+ os.chdir(root_dir)
+
+for dirpath, dirnames, filenames in os.walk(project_name):
+ # Ignore dirnames that start with '.'
+ for i, dirname in enumerate(dirnames):
+ if dirname.startswith('.'):
+ del dirnames[i]
+ if '__init__.py' in filenames:
+ pkg = dirpath.replace(os.path.sep, '.')
+ if os.path.altsep:
+ pkg = pkg.replace(os.path.altsep, '.')
+ packages.append(pkg)
+ elif filenames:
+ prefix = dirpath[(len(project_name) + 1):]
+ for f in filenames:
+ data_files.append(os.path.join(prefix, f))
+
+setup(
+ name='django-easyconfig',
+ version=__import__(project_name).__version__,
+ package_dir={project_name: project_name},
+ packages=packages,
+ package_data={project_name: data_files},
+ description='Module to make it easy to configure external Django apps.',
+ author='Peter Sanchez',
+ author_email='petersanchez@gmail.com',
+ license='BSD License',
+ url='http://bitbucket.org/petersanchez/django-easyconfig/',
+ long_description=long_description,
+ platforms=['any'],
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: BSD License',
+ 'Natural Language :: English',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Environment :: Web Environment',
+ ],
+)