Skip to content

Commit

Permalink
prepare 0.11.3
Browse files Browse the repository at this point in the history
  • Loading branch information
barseghyanartur committed May 9, 2017
1 parent d0d3b75 commit 46ba856
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 81 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ are used for versioning (schema follows below):
0.3.4 to 0.4).
- All backwards incompatible changes are mentioned in this document.

0.11.3
------
2017-05-10

- Concept of integration callbacks introduced and implemented for the
``drf_integration`` sub-package.

0.11.2
------
2017-05-09
Expand Down
63 changes: 60 additions & 3 deletions examples/simple/foo/fobi_form_callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,36 @@

import logging

from fobi.base import FormCallback, form_callback_registry
from fobi.base import (
form_callback_registry,
FormCallback,
integration_form_callback_registry,
IntegrationFormCallback,
)

from fobi.constants import (
CALLBACK_BEFORE_FORM_VALIDATION,
CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA,
CALLBACK_FORM_INVALID,
CALLBACK_FORM_VALID,
CALLBACK_FORM_VALID_AFTER_FORM_HANDLERS,
CALLBACK_FORM_INVALID
CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA,
)

from fobi.contrib.apps.drf_integration import UID as INTEGRATE_WITH

logger = logging.getLogger('fobi')

__all__ = (
'SaveAsFooItem',
'DummyInvalidCallback',
)

# *************************************************************
# *************************************************************
# ********************** Core callbacks ***********************
# *************************************************************
# *************************************************************

# *************************************************************
# **************** Save as foo callback ***********************
# *************************************************************
Expand Down Expand Up @@ -51,3 +65,46 @@ def callback(self, form_entry, request, form):


form_callback_registry.register(DummyInvalidCallback)

# *************************************************************
# *************************************************************
# ****************** DRF integration callbacks ****************
# *************************************************************
# *************************************************************


# *************************************************************
# **************** Save as foo callback ***********************
# *************************************************************


class DRFSaveAsFooItem(IntegrationFormCallback):
"""Save the form as a foo item, if certain conditions are met."""

stage = CALLBACK_FORM_VALID
integrate_with = INTEGRATE_WITH

def callback(self, form_entry, request, **kwargs):
"""Custom callback login comes here."""
logger.debug("Great! Your form is valid!")


integration_form_callback_registry.register(DRFSaveAsFooItem)

# *************************************************************
# **************** Save as foo callback ***********************
# *************************************************************


class DRFDummyInvalidCallback(IntegrationFormCallback):
"""Saves the form as a foo item, if certain conditions are met."""

stage = CALLBACK_FORM_INVALID
integrate_with = INTEGRATE_WITH

def callback(self, form_entry, request, **kwargs):
"""Custom callback login comes here."""
logger.debug("Damn! You've made a mistake, boy!")


integration_form_callback_registry.register(DRFDummyInvalidCallback)
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from distutils.version import LooseVersion
from setuptools import setup, find_packages

version = '0.11.2'
version = '0.11.3'

# ***************************************************************************
# ************************** Python version *********************************
Expand Down
4 changes: 2 additions & 2 deletions src/fobi/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
__title__ = 'django-fobi'
__version__ = '0.11.2'
__build__ = 0x00007d
__version__ = '0.11.3'
__build__ = 0x00007e
__author__ = 'Artur Barseghyan <[email protected]>'
__copyright__ = '2014-2017 Artur Barseghyan'
__license__ = 'GPL 2.0/LGPL 2.1'
Expand Down
131 changes: 105 additions & 26 deletions src/fobi/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,9 @@
'IntegrationFormHandlerPlugin',
'IntegrationFormHandlerPluginDataStorage',
'IntegrationFormHandlerPluginRegistry',
'IntegrationFormCallbackRegistry',
'IntegrationFormCallback',
'integration_form_callback_registry',
'run_form_handlers',
'run_form_wizard_handlers',
'theme_registry',
Expand Down Expand Up @@ -2060,7 +2063,7 @@ class IntegrationFormHandlerPlugin(BasePlugin):
is_hidden = False


class FormCallback(object):
class BaseFormCallback(object):
"""Base form callback."""

stage = None
Expand All @@ -2069,6 +2072,10 @@ def __init__(self):
"""Constructor."""
assert self.stage in CALLBACK_STAGES


class FormCallback(BaseFormCallback):
"""Form callback."""

def _callback(self, form_entry, request, form):
"""Callback (internal method).
Expand Down Expand Up @@ -2098,31 +2105,45 @@ def callback(self, form_entry, request, form):
"subclass.".format(self.__class__.__name__)
)

# def custom_field_instances_callback(self, integrate_with, form_entry,
# request, **kwargs):
# """Custom field instances callback.
#
# :param str integrate_with:
# :param fobi.models.FormEntry form_entry: Instance of
# ``fobi.models.FormEntry``.
# :param django.http.HttpRequest request:
# :param kwargs:
# """
# try:
# custom_callback = self.get_custom_field_instance_callback(
# integrate_with=integrate_with
# )
# return custom_callback.callback(
# form_entry=form_entry,
# request=request,
# **kwargs
# )
# except Exception as err:
# logger.debug(
# "Error in class %s. Details: %s",
# self.__class__.__name__,
# str(err)
# )

class IntegrationFormCallback(object):
"""Integration form callback."""

integrate_with = None

def __init__(self):
"""Constructor."""
assert self.stage in CALLBACK_STAGES
assert self.integrate_with is not None

def _callback(self, form_entry, request, **kwargs):
"""Callback (internal method).
Calling the ``callback`` method in a safe way.
"""
try:
return self.callback(form_entry, request, **kwargs)
except Exception as err:
logger.debug(
"Error in class %s. Details: %s",
self.__class__.__name__,
str(err)
)

def callback(self, form_entry, request, **kwargs):
"""Callback.
Custom callback code should be implemented here.
:param fobi.models.FormEntry form_entry: Instance of
``fobi.models.FormEntry``.
:param django.http.HttpRequest request:
:param django.forms.Form form:
"""
raise NotImplementedError(
"You should implement ``callback`` method in your {0} "
"subclass.".format(self.__class__.__name__)
)


class ClassProperty(property):
Expand Down Expand Up @@ -2507,6 +2528,61 @@ def get_callbacks(self, stage=None):
return callbacks


class IntegrationFormCallbackRegistry(object):
"""Registry of callbacks for integration plugins.
Holds callbacks for stages listed in the
``fobi.constants.CALLBACK_STAGES``.
"""

def __init__(self):
"""Constructor."""
self._registry = defaultdict(lambda: defaultdict(list))

@property
def registry(self):
return self._registry

def uidfy(self, cls):
"""Makes a UID string from the class given.
:param mixed cls:
:return string:
"""
return "{0}.{1}".format(cls.__module__, cls.__name__)

def register(self, cls):
"""Registers the plugin in the registry.
:param mixed cls:
"""
if not issubclass(cls, IntegrationFormCallback):
raise InvalidRegistryItemType(
"Invalid item type `{0}` for registry "
"`{1}`".format(cls, self.__class__)
)
if cls in self._registry[cls.integrate_with][cls.stage]:
return False
else:
self._registry[cls.integrate_with][cls.stage].append(cls)
return True

def get_callbacks(self, integrate_with, stage=None):
"""Get callbacks for the stage given.
:param str integrate_with:
:param string stage:
:return list:
"""
if stage:
return self._registry[integrate_with].get(stage, [])
else:
callbacks = []
for stage_callbacks in self._registry[integrate_with].values():
callbacks += stage_callbacks
return callbacks


class BasePluginWidgetRegistry(object):
"""Registry of plugins widgets (renderers)."""
type = None
Expand Down Expand Up @@ -2630,6 +2706,9 @@ class FormWizardHandlerPluginWidgetRegistry(BasePluginWidgetRegistry):
# Register action plugins by calling form_action_plugin_registry.register()
form_callback_registry = FormCallbackRegistry()

# Register action plugins by calling form_action_plugin_registry.register()
integration_form_callback_registry = IntegrationFormCallbackRegistry()

# Register plugin widgets by calling
# form_element_plugin_widget_registry.register()
form_element_plugin_widget_registry = FormElementPluginWidgetRegistry()
Expand Down
45 changes: 45 additions & 0 deletions src/fobi/contrib/apps/drf_integration/README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,51 @@ PUT
{DATA}
Callbacks
---------
Callbacks work just the same way the core callbacks work.

fobi_form_callbacks.py
~~~~~~~~~~~~~~~~~~~~~~
.. code-block:: python
from fobi.base import (
integration_form_callback_registry,
IntegrationFormCallback,
)
from fobi.constants import (
CALLBACK_BEFORE_FORM_VALIDATION,
CALLBACK_FORM_INVALID,
CALLBACK_FORM_VALID,
CALLBACK_FORM_VALID_AFTER_FORM_HANDLERS,
CALLBACK_FORM_VALID_BEFORE_SUBMIT_PLUGIN_FORM_DATA,
)
from fobi.contrib.apps.drf_integration import UID as INTEGRATE_WITH
class DRFSaveAsFooItem(IntegrationFormCallback):
"""Save the form as a foo item, if certain conditions are met."""
stage = CALLBACK_FORM_VALID
integrate_with = INTEGRATE_WITH
def callback(self, form_entry, request, **kwargs):
"""Custom callback login comes here."""
logger.debug("Great! Your form is valid!")
class DRFDummyInvalidCallback(IntegrationFormCallback):
"""Saves the form as a foo item, if certain conditions are met."""
stage = CALLBACK_FORM_INVALID
integrate_with = INTEGRATE_WITH
def callback(self, form_entry, request, **kwargs):
"""Custom callback login comes here."""
logger.debug("Damn! You've made a mistake, boy!")
Testing
-------
To test Django REST framework integration package only, run the following
Expand Down
14 changes: 6 additions & 8 deletions src/fobi/contrib/apps/drf_integration/TODOS.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ Must haves
instances. Do it this way and not the other way, since things get
complicated when we start to deal with wizards.
+ Find out how to handle further the submitted data? It should be in
accordance with fobi concepts of loosely couple parts. After successful
submission, the fobi form callbacks, handlers and that kind of things
accordance with ``fobi`` concepts of loosely couple parts. After successful
submission, the ``fobi`` form callbacks, handlers and that kind of things
should be fired for the given form entry. Thus, it should likely be the
same in this case. Probably each CustomFieldInstancePlugin should get
a method ``drf_submit_plugin_form_data``, which should mimic the
Expand All @@ -33,13 +33,11 @@ Should haves
------------
+ Find why HiddenInput tests fail (in terms of Django REST framework it's
a read-only field).
- Add custom field instance callback for handling data of the custom field
instances. Do it this way and not the other way, since things get
complicated when we start to deal with wizards.
- Add Integration form callbacks for handling data of the integration plugins.
- Add more fields (relation- and presentational- fields).
- Think of what to do with presentational fields (perhaps just display?)
- Somehow, the `file` plugin data, when submitted, isn't shown properly in the
posted data (by DRF), although is posted 100% correctly.
- Somehow, the ``file`` plugin data, when submitted, isn't shown properly in
the posted data (by DRF), although is posted 100% correctly.
- In the API form view, use memoize technique or cache the value somehow to
reduce the number of queries.

Expand All @@ -49,4 +47,4 @@ Could haves

Would haves
-----------
- Remove codebin.py at the end.
- Remove codebin.py at the end.
Loading

0 comments on commit 46ba856

Please sign in to comment.