Skip to content

Commit

Permalink
Merge pull request #3828 from yakky/feature/refactoring_circular_imports
Browse files Browse the repository at this point in the history
Refactor code to avoid circular imports
  • Loading branch information
yakky committed Feb 8, 2015
2 parents c94780f + 95d7e5b commit e0ce35d
Show file tree
Hide file tree
Showing 10 changed files with 214 additions and 214 deletions.
5 changes: 3 additions & 2 deletions cms/admin/change_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class CMSChangeList(ChangeList):
real_queryset = False

def __init__(self, request, *args, **kwargs):
from cms.utils.plugins import current_site
from cms.utils.helpers import current_site

self._current_site = current_site(request)
super(CMSChangeList, self).__init__(request, *args, **kwargs)
try:
Expand Down Expand Up @@ -76,7 +77,7 @@ def get_queryset(self, request):
return qs

def is_filtered(self):
from cms.utils.plugins import SITE_VAR
from cms.utils.helpers import SITE_VAR
lookup_params = self.params.copy() # a dictionary of the query string
for i in (ALL_VAR, ORDER_VAR, ORDER_TYPE_VAR, SEARCH_VAR, IS_POPUP_VAR, SITE_VAR, 'language', 'page_id'):
if i in lookup_params:
Expand Down
3 changes: 1 addition & 2 deletions cms/admin/pageadmin.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@
from cms.utils.admin import jsonify_request
from cms.utils.compat.dj import is_installed
from cms.utils.conf import get_cms_setting
from cms.utils.helpers import find_placeholder_relation
from cms.utils.helpers import find_placeholder_relation, current_site
from cms.utils.permissions import has_global_page_permission, has_generic_permission
from cms.utils.plugins import current_site
from cms.utils.urlutils import add_url_parameters, admin_reverse

require_POST = method_decorator(require_POST)
Expand Down
2 changes: 1 addition & 1 deletion cms/menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from cms.utils.i18n import get_fallback_languages, hide_untranslated
from cms.utils.page_resolver import get_page_queryset
from cms.utils.moderator import get_title_queryset, use_draft
from cms.utils.plugins import current_site
from cms.utils.helpers import current_site
from menus.base import Menu, NavigationNode, Modifier
from menus.menu_pool import menu_pool

Expand Down
6 changes: 2 additions & 4 deletions cms/models/pagemodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
from cms.utils import i18n, page as page_utils
from cms.utils.conf import get_cms_setting
from cms.utils.copy_plugins import copy_plugins_to
from cms.utils.helpers import reversion_register

from cms.utils.helpers import reversion_register, current_site
from menus.menu_pool import menu_pool
from treebeard.mp_tree import MP_Node

Expand Down Expand Up @@ -957,7 +956,6 @@ def get_template_name(self):

def has_view_permission(self, request, user=None):
from cms.models.permissionmodels import PagePermission, GlobalPagePermission
from cms.utils.plugins import current_site

if not user:
user = request.user
Expand Down Expand Up @@ -1191,7 +1189,7 @@ def rescan_placeholders(self):
Rescan and if necessary create placeholders in the current template.
"""
# inline import to prevent circular imports
from cms.utils.plugins import get_placeholders
from cms.utils.placeholder import get_placeholders

placeholders = get_placeholders(self.get_template())
found = {}
Expand Down
5 changes: 3 additions & 2 deletions cms/tests/placeholder.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@
from cms.toolbar.toolbar import CMSToolbar
from cms.utils.compat.tests import UnittestCompatMixin
from cms.utils.conf import get_cms_setting
from cms.utils.placeholder import PlaceholderNoAction, MLNGPlaceholderActions, get_placeholder_conf
from cms.utils.plugins import get_placeholders, assign_plugins
from cms.utils.placeholder import (PlaceholderNoAction, MLNGPlaceholderActions,
get_placeholder_conf, get_placeholders)
from cms.utils.plugins import assign_plugins
from cms.utils.urlutils import admin_reverse


Expand Down
2 changes: 1 addition & 1 deletion cms/tests/templatetags.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from cms.test_utils.testcases import CMSTestCase
from cms.toolbar.toolbar import CMSToolbar
from cms.utils import get_cms_setting, get_site_id
from cms.utils.plugins import get_placeholders
from cms.utils.placeholder import get_placeholders
from sekizai.context import SekizaiContext


Expand Down
19 changes: 19 additions & 0 deletions cms/utils/helpers.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# -*- coding: utf-8 -*-
from django.contrib.sites.models import SITE_CACHE, Site
from cms.utils.compat.dj import is_installed

SITE_VAR = "site__exact"


# modify reversions to match our needs if required...
def reversion_register(model_class, fields=None, follow=(), format="json", exclude_fields=None):
Expand Down Expand Up @@ -122,3 +125,19 @@ def __init__(self, fget):

def __get__(self, owner_self, owner_cls):
return self.fget(owner_cls)


def current_site(request):
if SITE_VAR in request.REQUEST:
site_pk = request.REQUEST[SITE_VAR]
else:
site_pk = request.session.get('cms_admin_site', None)
if site_pk:
try:
site = SITE_CACHE.get(site_pk) or Site.objects.get(pk=site_pk)
SITE_CACHE[site_pk] = site
return site
except Site.DoesNotExist:
return None
else:
return Site.objects.get_current()
9 changes: 6 additions & 3 deletions cms/utils/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ def has_page_add_permission(request):
target = request.GET.get('target', None)
position = request.GET.get('position', None)

from cms.utils.plugins import current_site
from cms.utils.helpers import current_site

site = current_site(request)

if target:
Expand Down Expand Up @@ -76,7 +77,8 @@ def has_page_add_permission(request):


def has_any_page_change_permissions(request):
from cms.utils.plugins import current_site
from cms.utils.helpers import current_site

if not request.user.is_authenticated():
return False
return request.user.is_superuser or PagePermission.objects.filter(
Expand All @@ -94,7 +96,8 @@ def has_page_change_permission(request):
In addition, if CMS_PERMISSION is enabled you also need to either have
global can_change permission or just on this page.
"""
from cms.utils.plugins import current_site
from cms.utils.helpers import current_site

opts = Page._meta
site = current_site(request)
global_change_perm = GlobalPagePermission.objects.user_has_change_permission(
Expand Down
209 changes: 174 additions & 35 deletions cms/utils/placeholder.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,59 @@
# -*- coding: utf-8 -*-
import operator
import warnings

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.db.models.query_utils import Q
from django.template import VariableNode, TemplateSyntaxError, NodeList
from django.template.loader import get_template
from django.template.loader_tags import ExtendsNode, BlockNode
try:
from django.template.loader_tags import ConstantIncludeNode as IncludeNode
except ImportError:
from django.template.loader_tags import IncludeNode
from django.utils import six
from django.utils.encoding import force_text
from sekizai.helpers import get_varname
from sekizai.helpers import get_varname, is_variable_extend_node

from cms.exceptions import DuplicatePlaceholderWarning
from cms.utils import get_cms_setting


def get_placeholder_conf(setting, placeholder, template=None, default=None):
"""
Returns the placeholder configuration for a given setting. The key would for
example be 'plugins' or 'name'.
If a template is given, it will try
CMS_PLACEHOLDER_CONF['template placeholder'] and
CMS_PLACEHOLDER_CONF['placeholder'], if no template is given only the latter
is checked.
"""
if placeholder:
keys = []
if template:
keys.append("%s %s" % (template, placeholder))
keys.append(placeholder)
for key in keys:
conf = get_cms_setting('PLACEHOLDER_CONF').get(key)
if not conf:
continue
value = conf.get(setting)
if value is not None:
return value
inherit = conf.get('inherit')
if inherit :
if ' ' in inherit:
inherit = inherit.split(' ')
else:
inherit = (None, inherit,)
value = get_placeholder_conf(setting, inherit[1], inherit[0], default)
if value is not None:
return value
return default


def get_toolbar_plugin_struct(plugins_list, slot, page, parent=None):
"""
Return the list of plugins to render in the toolbar.
Expand Down Expand Up @@ -47,40 +90,6 @@ def get_toolbar_plugin_struct(plugins_list, slot, page, parent=None):
return sorted(main_list, key=operator.itemgetter("module"))


def get_placeholder_conf(setting, placeholder, template=None, default=None):
"""
Returns the placeholder configuration for a given setting. The key would for
example be 'plugins' or 'name'.
If a template is given, it will try
CMS_PLACEHOLDER_CONF['template placeholder'] and
CMS_PLACEHOLDER_CONF['placeholder'], if no template is given only the latter
is checked.
"""
if placeholder:
keys = []
if template:
keys.append("%s %s" % (template, placeholder))
keys.append(placeholder)
for key in keys:
conf = get_cms_setting('PLACEHOLDER_CONF').get(key)
if not conf:
continue
value = conf.get(setting)
if value is not None:
return value
inherit = conf.get('inherit')
if inherit :
if ' ' in inherit:
inherit = inherit.split(' ')
else:
inherit = (None, inherit,)
value = get_placeholder_conf(setting, inherit[1], inherit[0], default)
if value is not None:
return value
return default


def validate_placeholder_name(name):
if not isinstance(name, six.string_types):
raise ImproperlyConfigured("Placeholder identifier names need to be of type string. ")
Expand Down Expand Up @@ -135,3 +144,133 @@ def restore_sekizai_context(context, changes):
sekizai_namespace = sekizai_container[key]
for value in values:
sekizai_namespace.append(value)


def _scan_placeholders(nodelist, current_block=None, ignore_blocks=None):
from cms.templatetags.cms_tags import Placeholder

placeholders = []
if ignore_blocks is None:
# List of BlockNode instances to ignore.
# This is important to avoid processing overriden block nodes.
ignore_blocks = []

for node in nodelist:
# check if this is a placeholder first
if isinstance(node, Placeholder):
placeholders.append(node.get_name())
elif isinstance(node, IncludeNode):
# if there's an error in the to-be-included template, node.template becomes None
if node.template:
# This is required for Django 1.7 but works on older version too
# Check if it quacks like a template object, if not
# presume is a template path and get the object out of it
if not callable(getattr(node.template, 'render', None)):
template = get_template(node.template.var)
else:
template = node.template
placeholders += _scan_placeholders(template.nodelist, current_block)
# handle {% extends ... %} tags
elif isinstance(node, ExtendsNode):
placeholders += _extend_nodelist(node)
# in block nodes we have to scan for super blocks
elif isinstance(node, VariableNode) and current_block:
if node.filter_expression.token == 'block.super':
if not hasattr(current_block.super, 'nodelist'):
raise TemplateSyntaxError("Cannot render block.super for blocks without a parent.")
placeholders += _scan_placeholders(current_block.super.nodelist, current_block.super)
# ignore nested blocks which are already handled
elif isinstance(node, BlockNode) and node.name in ignore_blocks:
continue
# if the node has the newly introduced 'child_nodelists' attribute, scan
# those attributes for nodelists and recurse them
elif hasattr(node, 'child_nodelists'):
for nodelist_name in node.child_nodelists:
if hasattr(node, nodelist_name):
subnodelist = getattr(node, nodelist_name)
if isinstance(subnodelist, NodeList):
if isinstance(node, BlockNode):
current_block = node
placeholders += _scan_placeholders(subnodelist, current_block, ignore_blocks)
# else just scan the node for nodelist instance attributes
else:
for attr in dir(node):
obj = getattr(node, attr)
if isinstance(obj, NodeList):
if isinstance(node, BlockNode):
current_block = node
placeholders += _scan_placeholders(obj, current_block, ignore_blocks)
return placeholders


def get_placeholders(template):
compiled_template = get_template(template)
placeholders = _scan_placeholders(compiled_template.nodelist)
clean_placeholders = []
for placeholder in placeholders:
if placeholder in clean_placeholders:
warnings.warn("Duplicate {{% placeholder \"{0}\" %}} "
"in template {1}."
.format(placeholder, template, placeholder),
DuplicatePlaceholderWarning)
else:
validate_placeholder_name(placeholder)
clean_placeholders.append(placeholder)
return clean_placeholders


def _extend_nodelist(extend_node):
"""
Returns a list of placeholders found in the parent template(s) of this
ExtendsNode
"""
# we don't support variable extensions
if is_variable_extend_node(extend_node):
return []
# This is a dictionary mapping all BlockNode instances found in the template that contains extend_node
blocks = dict(extend_node.blocks)
_extend_blocks(extend_node, blocks)
placeholders = []

for block in blocks.values():
placeholders += _scan_placeholders(block.nodelist, block, blocks.keys())

# Scan topmost template for placeholder outside of blocks
parent_template = _find_topmost_template(extend_node)
placeholders += _scan_placeholders(parent_template.nodelist, None, blocks.keys())
return placeholders


def _find_topmost_template(extend_node):
parent_template = extend_node.get_parent({})
for node in parent_template.nodelist.get_nodes_by_type(ExtendsNode):
# Their can only be one extend block in a template, otherwise django raises an exception
return _find_topmost_template(node)
# No ExtendsNode
return extend_node.get_parent({})


def _extend_blocks(extend_node, blocks):
"""
Extends the dictionary `blocks` with *new* blocks in the parent node (recursive)
"""
# we don't support variable extensions
if is_variable_extend_node(extend_node):
return
parent = extend_node.get_parent(None)
# Search for new blocks
for node in parent.nodelist.get_nodes_by_type(BlockNode):
if not node.name in blocks:
blocks[node.name] = node
else:
# set this node as the super node (for {{ block.super }})
block = blocks[node.name]
seen_supers = []
while hasattr(block.super, 'nodelist') and block.super not in seen_supers:
seen_supers.append(block.super)
block = block.super
block.super = node
# search for further ExtendsNodes
for node in parent.nodelist.get_nodes_by_type(ExtendsNode):
_extend_blocks(node, blocks)
break

0 comments on commit e0ce35d

Please sign in to comment.