# HG changeset patch # User Peter Sanchez # Date 1293757080 28800 # Thu Dec 30 16:58:00 2010 -0800 # Node ID be72082c589780691d3c3829866e293526e81682 # Parent 0000000000000000000000000000000000000000 Initial commit.. diff --git a/.hgignore b/.hgignore new file mode 100644 --- /dev/null +++ b/.hgignore @@ -0,0 +1,5 @@ +syntax:glob +.svn +.hgsvn +.*.swp +**.pyc diff --git a/LICENSE b/LICENSE new file mode 100644 --- /dev/null +++ b/LICENSE @@ -0,0 +1,32 @@ +Copyright (c) 2010, Peter Sanchez +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. diff --git a/README.txt b/README.txt new file mode 100644 --- /dev/null +++ b/README.txt @@ -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 . 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. diff --git a/easyconfig/__init__.py b/easyconfig/__init__.py new file mode 100644 --- /dev/null +++ b/easyconfig/__init__.py @@ -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 diff --git a/setup.py b/setup.py new file mode 100644 --- /dev/null +++ b/setup.py @@ -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', + ], +)