Ejemplo n.º 1
0
    def get_form_class(self):
        """
        Returns the form class for this Feature Class.
        """
        try:
            klass = get_class(self.form)
        except Exception, e:
            raise (FeatureConfigurationError(
                "Feature class %s is not configured with a valid form class. \
Could not import %s.\n%s" % (self._model.__name__, self.form, e)), 
                   None, 
                sys.exc_info()[2])
Ejemplo n.º 2
0
    def get_form_class(self):
        """
        Returns the form class for this Feature Class.
        """
        try:
            klass = get_class(self.form)
        except Exception as e:
            raise FeatureConfigurationError(
                "Feature class %s is not configured with a valid form class. \
Could not import %s.\n%s" % (self._model.__name__, self.form, e))

        if not issubclass(klass, FeatureForm):
            raise FeatureConfigurationError(
                "Feature class %s's form is not a subclass of \
features.forms.FeatureForm." % (self._model.__name__, ))

        return klass
Ejemplo n.º 3
0
    def get_valid_children(self):
        if not self.valid_children:
            raise FeatureConfigurationError(
                "%r is not a properly configured FeatureCollection" % (self._model))

        valid_child_classes = []
        for vc in self.valid_children:
            try:
                vc_class = get_class(vc)
            except:
                raise FeatureConfigurationError(
                        "Error trying to import module %s" % vc) 

            from features.models import Feature
            if not issubclass(vc_class, Feature):
                raise FeatureConfigurationError(
                        "%r is not a Feature; can't be a child" % vc) 

            valid_child_classes.append(vc_class)

        return valid_child_classes
Ejemplo n.º 4
0
    def get_valid_children(self):
        if not self.valid_children:
            raise FeatureConfigurationError(
                "%r is not a properly configured FeatureCollection" %
                (self._model))

        valid_child_classes = []
        for vc in self.valid_children:
            try:
                vc_class = get_class(vc)
            except:
                raise FeatureConfigurationError(
                    "Error trying to import module %s" % vc)

            from features.models import Feature
            if not issubclass(vc_class, Feature):
                raise FeatureConfigurationError(
                    "%r is not a Feature; can't be a child" % vc)

            valid_child_classes.append(vc_class)

        return valid_child_classes
 def testNoDots(self):
     with self.assertRaises(ValueError): 
         get_class('hello')
 def testExistent(self):
     cls = get_class('ConfigParser.RawConfigParser')
     import ConfigParser
     
     self.assertEqual(cls, ConfigParser.RawConfigParser, 'Got the wrong class')
 def testNonExistent(self):
     with self.assertRaises(AttributeError):
         get_class('sys.poodoo')
Ejemplo n.º 8
0
 def testNoDots(self):
     with self.assertRaises(ValueError):
         get_class('hello')
Ejemplo n.º 9
0
    def testExistent(self):
        cls = get_class('ConfigParser.RawConfigParser')
        import ConfigParser

        self.assertEqual(cls, ConfigParser.RawConfigParser,
                         'Got the wrong class')
Ejemplo n.º 10
0
 def testNonExistent(self):
     with self.assertRaises(AttributeError):
         get_class('sys.poodoo')
Ejemplo n.º 11
0
    def __init__(self, model):

        # Import down here to avoid circular reference
        from features.models import Feature, FeatureCollection

        # call this here to ensure that permsissions get created
        #enable_sharing()

        if not issubclass(model, Feature):
            raise FeatureConfigurationError('Is not a subclass of \
features.models.Feature')

        self._model = model
        name = model.__name__

        if not getattr(model, 'Options', False):
            raise FeatureConfigurationError(
                'Have not defined Options inner-class on registered feature \
class %s' % (name, ))

        self._options = model.Options

        if not hasattr(self._options, 'form'):
            raise FeatureConfigurationError(
                "Feature class %s is not configured with a form class. \
To specify, add a `form` property to its Options inner-class." % (name, ))

        if not isinstance(self._options.form, str):
            raise FeatureConfigurationError(
                "Feature class %s is configured with a form property that is \
not a string path." % (name, ))

        self.form = self._options.form
        """
        Path to FeatureForm used to edit this class.
        """

        self.slug = slugify(name)
        """
        Name used in the url path to this feature as well as part of
        the Feature's uid
        """

        self.verbose_name = getattr(self._options, 'verbose_name', name)
        """
        Name specified or derived from the feature class name used
        in the user interface for representing this feature class.
        """

        self.form_template = getattr(self._options, 'form_template',
                                     'features/form.html')
        """
        Location of the template that should be used to render forms
        when editing or creating new instances of this feature class.
        """

        self.form_context = getattr(self._options, 'form_context', {})
        """
        Context to merge with default context items when rendering
        templates to create or modify features of this class.
        """

        self.show_context = getattr(self._options, 'show_context', {})
        """
        Context to merge with default context items when rendering
        templates to view information about instances of this feature class.
        """

        self.icon_url = getattr(self._options, 'icon_url', None)
        """
        Optional; URL to 16x16 icon to use in kmltree
        Use full URL or relative to MEDIA_URL
        """

        self.links = []
        """
        Links associated with this class.
        """

        opts_links = getattr(self._options, 'links', False)
        if opts_links:
            self.links.extend(opts_links)

        self.enable_copy = getattr(self._options, 'disable_copy', True)
        """
        Enable copying features. Uses the feature class' copy() method.
        Defaults to True.
        """

        # Add a copy method unless disabled
        if self.enable_copy:
            self.links.insert(
                0,
                edit('Copy',
                     'features.views.copy',
                     select='multiple single',
                     edits_original=False))

        confirm = "Are you sure you want to delete this feature and it's contents?"

        # Add a multi-share generic link
        # TODO when the share_form view takes multiple instances
        #  we can make sharing a generic link
        #self.links.insert(0, edit('Share',
        #    'features.views.share_form',
        #    select='multiple single',
        #    method='POST',
        #    edits_original=True,
        #))

        # Add a multi-delete generic link
        self.links.insert(
            0,
            edit(
                'Delete',
                'features.views.multi_delete',
                select='multiple single',
                method='DELETE',
                edits_original=True,
                confirm=confirm,
            ))

        # Add a staticmap generic link
        # export_png = getattr(self._options, 'export_png', True)
        # RDH - the above code will always trigger unless mp-drawing module explicitly set to False.
        if getattr(self._options, 'export_png', False):
            # TODO: Bring in the staticmap module
            logger.warning("Uncomment the following code")
            # self.links.insert(0, alternate('PNG Image',
            #     'staticmap.views.staticmap_link',
            #     select='multiple single',
            #     method='GET',
            # ))

        # Add a geojson generic link
        export_geojson = getattr(self._options, 'export_geojson', True)
        if export_geojson:
            self.links.insert(
                0,
                alternate(
                    'GeoJSON',
                    'features.views.geojson_link',
                    select='multiple single',
                    method='GET',
                ))

        self.valid_children = getattr(self._options, 'valid_children', None)
        """
        valid child classes for the feature container
        """
        if self.valid_children and not issubclass(self._model,
                                                  FeatureCollection):
            raise FeatureConfigurationError("valid_children Option only \
                    for FeatureCollection classes")

        self.manipulators = []
        """
        Required manipulators applied to user input geometries
        """
        manipulators = getattr(self._options, 'manipulators', [])
        for m in manipulators:
            try:
                manip = get_class(m)
            except Exception as e:
                # Don't lose the original exception, fake a PEP3134 exception
                # chain (too bad we're not Py3k)
                t, v, tb = sys.exc_info()
                s = "Error trying to import module %s" % m
                raise FeatureConfigurationError(s, t, v, tb)

            # Test that manipulator is compatible with this Feature Class
            geom_field = self._model.geometry_final._field.__class__.__name__
            if geom_field not in manip.Options.supported_geom_fields:
                raise FeatureConfigurationError(
                    "%s does not support %s geometry types (only %r)" %
                    (m, geom_field, manip.Options.supported_geom_fields))

            #logger.debug("Added required manipulator %s" % m)
            self.manipulators.append(manip)

        self.optional_manipulators = []
        """
        Optional manipulators that may be applied to user input geometries
        """
        optional_manipulators = getattr(self._options, 'optional_manipulators',
                                        [])
        for m in optional_manipulators:
            try:
                manip = get_class(m)
            except:
                raise FeatureConfigurationError(
                    "Error trying to import module %s" % m)

            # Test that manipulator is compatible with this Feature Class
            geom_field = self._model.geometry_final._field.__class__.__name__
            try:
                if geom_field not in manip.Options.supported_geom_fields:
                    raise FeatureConfigurationError(
                        "%s does not support %s geometry types (only %r)" %
                        (m, geom_field, manip.Options.supported_geom_fields))
            except AttributeError:
                raise FeatureConfigurationError(
                    "%s is not set up properly; must have "
                    "Options.supported_geom_fields list." % m)

            #logger.debug("Added optional manipulator %s" % m)
            self.optional_manipulators.append(manip)

        self.enable_kml = True
        """
        Enable kml visualization of features.  Defaults to True.
        """
        # Add a kml link by default
        if self.enable_kml:
            self.links.insert(
                0,
                alternate('KML',
                          'features.views.kml',
                          select='multiple single'))
            self.links.insert(
                0,
                alternate('KMZ',
                          'features.views.kmz',
                          select='multiple single'))

        for link in self.links:
            if self._model not in link.models:
                link.models.append(self._model)
Ejemplo n.º 12
0
    def __init__(self,
                 rel,
                 title,
                 view,
                 method='GET',
                 select='single',
                 type=None,
                 slug=None,
                 generic=False,
                 models=None,
                 extra_kwargs={},
                 confirm=False,
                 edits_original=None,
                 must_own=False,
                 limit_to_groups=None):

        self.rel = rel
        """Type of link - alternate, related, edit, or edit_form.
        """

        try:
            self.view = get_class(view)
            """
            View function handling requests to this link.
            """
        except Exception as err:
            msg = 'Link "%s" configured with invalid path to view %s' % (title,
                                                                         view)
            msg += '\n%s\n' % str(err)
            if "cannot import" in str(err):
                msg += "(Possible cause: importing Features at the top level in views.py can cause"
                msg += " circular dependencies; Try to import Features within the view function)"

            raise FeatureConfigurationError(msg)

        self.title = title
        """
        Human-readable title for the link to be shown in the user interface.
        """

        self.method = method
        """
        For rel=edit links, identifies whether a form should be requested or
        that url should just be POST'ed to.
        """

        self.type = type
        """
        MIME type of this link, useful for alternate links. May in the future
        be used to automatically assign an icon in the dropdown Export menu.
        """

        self.slug = slug
        """
        Part of this link's path.
        """

        self.select = select
        """
        Determines whether this link accepts requests with single or multiple
        instances of a feature class. Valid values are "single", "multiple",
        "single multiple", and "multiple single".
        """

        self.extra_kwargs = extra_kwargs
        """
        Extra keyword arguments to pass to the view.
        """

        self.generic = generic
        """
        Whether this view can be applied to multiple feature classes.
        """

        self.models = models
        """
        List of feature classes that a this view can be applied to, if it is
        generic.
        """

        self.confirm = confirm
        """
        Confirmation message to show the user before POSTing to rel=edit link
        """

        self.edits_original = edits_original
        """
        Set to false for editing links that create a copy of the original.
        This will allow users who do not own the instance(s) but can view them
        perform the action.
        """

        self.must_own = must_own
        if self.edits_original:
            self.must_own = True
        """
        Whether this link should be accessible to non-owners.
        Default link behavior is False; i.e. Link can be used for shared features
        as well as for user-owned features.
        If edits_original is true, this implies must_own = True as well.
        """

        self.limit_to_groups = limit_to_groups
        """
        Allows you to specify groups (a list of group names)
        that should have access to the link.
        Default is None; i.e. All users have link access regardless of group membership
        """

        if self.models is None:
            self.models = []

        # Make sure title isn't empty
        if self.title is '':
            raise FeatureConfigurationError('Link title is empty')
        valid_options = ('single', 'multiple', 'single multiple',
                         'multiple single')
        # Check for valid 'select' kwarg
        if self.select not in valid_options:
            raise FeatureConfigurationError(
                'Link specified with invalid select option "%s"' %
                (self.select, ))
        # Create slug from the title unless a custom slug is specified
        if self.slug is None:
            self.slug = slugify(title)
        # Make sure the view has the right signature
        self._validate_view(self.view)
Ejemplo n.º 13
0
    def __init__(self, model):

        # Import down here to avoid circular reference
        from features.models import Feature, FeatureCollection

        # call this here to ensure that permsissions get created
        #enable_sharing()

        if not issubclass(model, Feature):
            raise FeatureConfigurationError('Is not a subclass of \
features.models.Feature')

        self._model = model
        name = model.__name__

        if not getattr(model, 'Options', False):
            raise FeatureConfigurationError(
                'Have not defined Options inner-class on registered feature \
class %s' % (name, ))

        self._options = model.Options

        if not hasattr(self._options, 'form'):
            raise FeatureConfigurationError(
                "Feature class %s is not configured with a form class. \
To specify, add a `form` property to its Options inner-class." % (name,))

        if not isinstance(self._options.form, str):
            raise FeatureConfigurationError(
                "Feature class %s is configured with a form property that is \
not a string path." % (name,))

        self.form = self._options.form
        """
        Path to FeatureForm used to edit this class.
        """

        self.slug = slugify(name)
        """
        Name used in the url path to this feature as well as part of
        the Feature's uid
        """

        self.verbose_name = getattr(self._options, 'verbose_name', name)
        """
        Name specified or derived from the feature class name used
        in the user interface for representing this feature class.
        """

        self.form_template = getattr(self._options, 'form_template',
            'features/form.html')
        """
        Location of the template that should be used to render forms
        when editing or creating new instances of this feature class.
        """

        self.form_context = getattr(self._options, 'form_context', {})
        """
        Context to merge with default context items when rendering
        templates to create or modify features of this class.
        """

        self.show_context = getattr(self._options, 'show_context', {})
        """
        Context to merge with default context items when rendering
        templates to view information about instances of this feature class.
        """

        self.icon_url = getattr(self._options, 'icon_url', None)
        """
        Optional; URL to 16x16 icon to use in kmltree
        Use full URL or relative to MEDIA_URL
        """

        self.links = []
        """
        Links associated with this class.
        """

        opts_links = getattr(self._options, 'links', False)
        if opts_links:
            self.links.extend(opts_links)

        self.enable_copy = getattr(self._options, 'disable_copy', True)
        """
        Enable copying features. Uses the feature class' copy() method.
        Defaults to True.
        """

        # Add a copy method unless disabled
        if self.enable_copy:
            self.links.insert(0, edit('Copy',
                'features.views.copy',
                select='multiple single',
                edits_original=False))

        confirm = "Are you sure you want to delete this feature and it's contents?"

        # Add a multi-share generic link
        # TODO when the share_form view takes multiple instances
        #  we can make sharing a generic link
        #self.links.insert(0, edit('Share',
        #    'features.views.share_form',
        #    select='multiple single',
        #    method='POST',
        #    edits_original=True,
        #))

        # Add a multi-delete generic link
        self.links.insert(0, edit('Delete',
            'features.views.multi_delete',
            select='multiple single',
            method='DELETE',
            edits_original=True,
            confirm=confirm,
        ))

        # Add a staticmap generic link
        export_png = getattr(self._options, 'export_png', True)
        if export_png:
            # TODO: Bring in the staticmap module
            logger.warning("Uncomment the following code")
#             self.links.insert(0, alternate('PNG Image',
#                 'staticmap.views.staticmap_link',
#                 select='multiple single',
#                 method='GET',
#             ))

        # Add a geojson generic link
        export_geojson = getattr(self._options, 'export_geojson', True)
        if export_geojson:
            self.links.insert(0, alternate('GeoJSON',
                'features.views.geojson_link',
                select='multiple single',
                method='GET',
            ))

        self.valid_children = getattr(self._options, 'valid_children', None)
        """
        valid child classes for the feature container
        """
        if self.valid_children and not issubclass(self._model, FeatureCollection):
            raise FeatureConfigurationError("valid_children Option only \
                    for FeatureCollection classes")

        self.manipulators = []
        """
        Required manipulators applied to user input geometries
        """
        manipulators = getattr(self._options, 'manipulators', [])
        for m in manipulators:
            try:
                manip = get_class(m)
            except Exception, e:
                # Don't lose the original exception, fake a PEP3134 exception
                # chain (too bad we're not Py3k)
                t, v, tb = sys.exc_info()
                s = "Error trying to import module %s" % m
                raise FeatureConfigurationError, (s, t, v), tb

            # Test that manipulator is compatible with this Feature Class
            geom_field = self._model.geometry_final._field.__class__.__name__
            if geom_field not in manip.Options.supported_geom_fields:
                raise FeatureConfigurationError("%s does not support %s geometry types (only %r)" %
                        (m, geom_field, manip.Options.supported_geom_fields))

            #logger.debug("Added required manipulator %s" % m)
            self.manipulators.append(manip)
Ejemplo n.º 14
0
    def __init__(self, rel, title, view, method='GET', select='single', 
        type=None, slug=None, generic=False, models=None, extra_kwargs={}, 
        confirm=False, edits_original=None, must_own=False, 
        limit_to_groups=None):

        self.rel = rel
        """Type of link - alternate, related, edit, or edit_form.
        """

        try:
            self.view = get_class(view)
            """
            View function handling requests to this link.
            """
        except Exception as err:
            msg = 'Link "%s" configured with invalid path to view %s' % (title, view)
            msg += '\n%s\n' % str(err)
            if "cannot import" in str(err):
                msg += "(Possible cause: importing Features at the top level in views.py can cause"
                msg += " circular dependencies; Try to import Features within the view function)"

            raise FeatureConfigurationError(msg)

        self.title = title
        """
        Human-readable title for the link to be shown in the user interface.
        """

        self.method = method
        """
        For rel=edit links, identifies whether a form should be requested or 
        that url should just be POST'ed to.
        """

        self.type = type
        """
        MIME type of this link, useful for alternate links. May in the future
        be used to automatically assign an icon in the dropdown Export menu.
        """

        self.slug = slug
        """
        Part of this link's path.
        """

        self.select = select
        """
        Determines whether this link accepts requests with single or multiple
        instances of a feature class. Valid values are "single", "multiple",
        "single multiple", and "multiple single". 
        """

        self.extra_kwargs = extra_kwargs
        """
        Extra keyword arguments to pass to the view.
        """

        self.generic = generic
        """
        Whether this view can be applied to multiple feature classes.
        """

        self.models = models
        """
        List of feature classes that a this view can be applied to, if it is 
        generic.
        """

        self.confirm = confirm
        """
        Confirmation message to show the user before POSTing to rel=edit link
        """

        self.edits_original = edits_original
        """
        Set to false for editing links that create a copy of the original. 
        This will allow users who do not own the instance(s) but can view them
        perform the action.
        """

        self.must_own = must_own
        if self.edits_original:
            self.must_own = True
        """
        Whether this link should be accessible to non-owners.
        Default link behavior is False; i.e. Link can be used for shared features
        as well as for user-owned features. 
        If edits_original is true, this implies must_own = True as well.
        """

        self.limit_to_groups = limit_to_groups
        """
        Allows you to specify groups (a list of group names) 
        that should have access to the link.
        Default is None; i.e. All users have link access regardless of group membership
        """

        if self.models is None:
            self.models = []

        # Make sure title isn't empty
        if self.title is '':
            raise FeatureConfigurationError('Link title is empty')
        valid_options = ('single', 'multiple', 'single multiple', 
            'multiple single')
        # Check for valid 'select' kwarg
        if self.select not in valid_options:
            raise FeatureConfigurationError(
                'Link specified with invalid select option "%s"' % (
                    self.select, ))
        # Create slug from the title unless a custom slug is specified
        if self.slug is None:
            self.slug = slugify(title)
        # Make sure the view has the right signature
        self._validate_view(self.view)