Skip to content

Commit

Permalink
Adding a function that filters only the available apps from a list of…
Browse files Browse the repository at this point in the history
… given apps to allow for more dynamic loading behavior of an app
  • Loading branch information
Tim Schneider committed Mar 15, 2016
1 parent c83fb70 commit ff7157c
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 34 deletions.
88 changes: 57 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,36 +43,24 @@ To register elements with the Registry you therefore need to implement the appro
`call_function_subpath` in an app that is listed in the `INSTALLED_APPS`. The implemented function then needs to call
the `add_item` function on the passed registry.

### MultiListPartRegistry(object)
The following functions are available:

#### add_part(list, part)
Adds the part given by the `part` parameter to the list with the name given by the `list` parameter.

#### get(list)
Returns the parts in the list with the name given by the `list` parameter. The elements are sorted before they are
returned.

#### sort_parts(parts)
Can be overwritten to define a custom ordering of the parts. The default function simply returns the list unordered.

#### load()
When called, the class is initialized and loads the available parts into its list cache. Does nothing if the `load()`
was already called. Is called automatically by the `get()` function. There is no need to call it explicitly unless you
want to initialize the class before the first list is retrieved.

#### reset()
Resets the Registry to its initial state so that the parts will be reloaded the next time the `load()` function is
called. Usually there is no need to call this as it only adds extra overhead when the parts need to be loaded again.

### SingleListPartRegistry(MultiListPartRegistry)
The following functions are additionally available:

#### add_part(part)
Adds the part given by the `part` parameter to the list.

#### get()
Returns the parts in the list. The elements are sorted before they are returned.
To further simplify the usage of dynamic apps, the app provides a `filter_available_apps` function that filters a list
of possible apps and returns only the ones that are available in the current installation. This allows for a highly
dynamic configuration of django projects by allowing certain apps to be installed selectively. Use it in your
`settings.py` to dynamically add the available apps to your `INSTALLED_APPS`

#### File: settings.py
from django_appregistration import filter_available_apps
INSTALLED_APPS = [
'imported_app1',
'imported_app2',
'imported_app3',
...
] + filter_available_apps(
'optional_app1',
'optional_app2',
'optional_app3',
...
)

## Example
Here is an implementation example with a Registry implemented in the `extendable_app` app and an app `extending_app`
Expand Down Expand Up @@ -107,11 +95,49 @@ The objects can be retrieved like so:
other_parts = MyRegistry.get('other') # retrieves the `other` list



##API

### MultiListPartRegistry(object)
The following functions are available:

#### add_part(list, part)
Adds the part given by the `part` parameter to the list with the name given by the `list` parameter.

#### get(list)
Returns the parts in the list with the name given by the `list` parameter. The elements are sorted before they are
returned.

#### sort_parts(parts)
Can be overwritten to define a custom ordering of the parts. The default function simply returns the list unordered.

#### load()
When called, the class is initialized and loads the available parts into its list cache. Does nothing if the `load()`
was already called. Is called automatically by the `get()` function. There is no need to call it explicitly unless you
want to initialize the class before the first list is retrieved.

#### reset()
Resets the Registry to its initial state so that the parts will be reloaded the next time the `load()` function is
called. Usually there is no need to call this as it only adds extra overhead when the parts need to be loaded again.

### SingleListPartRegistry(MultiListPartRegistry)
The following functions are additionally available:

#### add_part(part)
Adds the part given by the `part` parameter to the list.

#### get()
Returns the parts in the list. The elements are sorted before they are returned.


##Running the tests

The included tests can be run standalone by running the `tests/runtests.py` script. You need to have Django and
mock installed for them to run. If you also want to run coverage, you need to install it before running the tests

###v.0.0.4
- Adding the `filter_available_apps` function that checks a list of given apps for their availability.

###v.0.0.3
- Bugfix: Also moved the `lock` and the `loaded` attributes into the meta class

Expand All @@ -128,4 +154,4 @@ used the same list resulting in element mixtures if more than one registry was u


## Maintainers
This Project is maintaned by [Northbridge Development Konrad & Schneider GbR](http://www.northbridge-development.de) Softwareentwicklung
This Project is maintained by [Northbridge Development Konrad & Schneider GbR](http://www.northbridge-development.de) Softwareentwicklung.
20 changes: 19 additions & 1 deletion django_appregistration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.utils.encoding import force_text
import imp
from six import with_metaclass

__author__ = 'Tim Schneider <tim.schneider@northbridge-development.de>'
Expand Down Expand Up @@ -82,4 +83,21 @@ def add_part(cls, part):

@classmethod
def get(cls):
return super(SingleListPartRegistry, cls).get('')
return super(SingleListPartRegistry, cls).get('')


def filter_available_apps(*app_list):
'''
Checks for the availability of the given apps and returns a list with only the available apps
:param app_list: The list of the candidate apps to check for
:return: The list of apps from the candidate list that are actually available
'''

available_apps = []
for app in app_list:
try:
imp.find_module(app)
available_apps.append(app)
except ImportError:
pass
return available_apps
20 changes: 19 additions & 1 deletion django_appregistration/tests/test___init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from django.test import TestCase
from mock import patch, MagicMock
from django_appregistration import MultiListPartRegistry, SingleListPartRegistry
from django_appregistration import MultiListPartRegistry, SingleListPartRegistry, filter_available_apps

try:
from django.test import override_settings
Expand Down Expand Up @@ -198,3 +198,21 @@ class Registry2(SingleListPartRegistry):

self.assertEqual(len(Registry1.get()), 1)
self.assertEqual(len(Registry2.get()), 1)


class FilterAvailableAppsTestCase(TestCase):
def test_filter_available_apps_list(self):
test_apps = (
'django',
'non_existent',
'django_appregistration',
)
desired_result = [
'django',
'django_appregistration',
]

self.assertListEqual(
desired_result,
filter_available_apps(*test_apps)
)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

setup(
name='django-appregistration',
version='0.0.3',
version='0.0.4',
packages=find_packages(exclude=['*.tests',]),
include_package_data=True,
install_requires=['Django >=1.6',],
Expand Down

0 comments on commit ff7157c

Please sign in to comment.