[Python-modules-commits] [django-sitetree] 01/06: Import django-sitetree_1.7.0.orig.tar.gz
Michael Fladischer
fladi at moszumanska.debian.org
Sun Dec 25 14:01:19 UTC 2016
This is an automated email from the git hooks/post-receive script.
fladi pushed a commit to branch master
in repository django-sitetree.
commit c70849aabf1d13a99b861419f172c9631ac26f7e
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date: Sun Dec 25 11:04:36 2016 +0100
Import django-sitetree_1.7.0.orig.tar.gz
---
.coveragerc | 2 +-
.travis.yml | 17 +-
AUTHORS | 1 +
CHANGELOG | 14 +-
INSTALL | 31 +
MANIFEST.in | 14 +-
README.rst | 20 +-
docs/source/index.rst | 3 +-
docs/source/tags.rst | 6 +-
setup.cfg | 1 +
setup.py | 6 +
sitetree/__init__.py | 4 +-
sitetree/fields.py | 18 +-
.../management/commands/sitetree_resync_apps.py | 2 +-
sitetree/management/commands/sitetreeload.py | 18 +-
sitetree/runtests.py | 53 +-
sitetree/settings.py | 17 +-
sitetree/sitetreeapp.py | 740 ++++++++++------
sitetree/templatetags/sitetree.py | 20 +-
sitetree/tests.py | 952 ---------------------
sitetree/tests/__init__.py | 1 +
sitetree/tests/common.py | 15 +
sitetree/tests/conftest.py | 232 +++++
sitetree/tests/sitetrees.py | 11 +
sitetree/tests/test_admin.py | 124 +++
sitetree/tests/test_dynamic.py | 87 ++
sitetree/tests/test_forms.py | 40 +
sitetree/tests/test_management.py | 87 ++
sitetree/tests/test_models.py | 54 ++
sitetree/tests/test_other.py | 62 ++
sitetree/tests/test_templatetags.py | 339 ++++++++
sitetree/tests/test_utils.py | 122 +++
sitetree/tests/urls.py | 13 +
sitetree/utils.py | 59 +-
tox.ini | 20 +-
35 files changed, 1822 insertions(+), 1383 deletions(-)
diff --git a/.coveragerc b/.coveragerc
index 70d6a58..1104297 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,3 +1,3 @@
[run]
include = sitetree/*
-omit = sitetree/migrations/*, sitetree/south_migrations/*, sitetree/runtests.py, sitetree/tests.py, sitetree/config.py
+omit = sitetree/migrations/*, sitetree/south_migrations/*, sitetree/tests/*, sitetree/runtests.py, sitetree/config.py
diff --git a/.travis.yml b/.travis.yml
index 4f1bbed..751e85a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,33 +11,22 @@ env:
- DJANGO="Django>=1.9,<1.10"
- DJANGO="Django>=1.8.6,<1.9"
- DJANGO="Django>=1.7,<1.8"
- - DJANGO="Django>=1.6,<1.7"
- - DJANGO="Django>=1.4,<1.5"
-
+
install:
- pip install -U coverage coveralls $DJANGO
-
-script: coverage run -a --source=sitetree sitetree/runtests.py
+
+script: coverage run -a --source=sitetree setup.py test
matrix:
exclude:
- python: 3.5
env: DJANGO="Django>=1.7,<1.8"
- - python: 3.5
- env: DJANGO="Django>=1.6,<1.7"
- - python: 3.5
- env: DJANGO="Django>=1.4,<1.5"
-
- - python: 3.4
- env: DJANGO="Django>=1.4,<1.5"
- python: 3.3
env: DJANGO="Django>=1.10,<1.11"
- python: 3.3
env: DJANGO="Django>=1.9,<1.10"
- - python: 3.3
- env: DJANGO="Django>=1.4,<1.5"
after_success:
coveralls
diff --git a/AUTHORS b/AUTHORS
index e0f0120..2852226 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -36,6 +36,7 @@ Ben Cole <https://github.com/wengole>
Vitaliy Ivanov <https://github.com/vit-ivanov>
Sergey Maranchuk <https://github.com/slav0nic>
Martey Dodoo <https://github.com/martey>
+Michał Suszko <https://github.com/msuszko>
Translators
diff --git a/CHANGELOG b/CHANGELOG
index cee1011..96f4ea1 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -2,6 +2,18 @@ django-sitetree changelog
=========================
+v1.7.0
+------
+* IMPORTANT: Caching reworked.
+* IMPORTANT: Dropped Django 1.5, 1.6 support (will not be tested anymore).
++ Added `ITEMS_FIELD_ROOT_ID` setting (see #205).
+* Reduced DB hits for trees with lots of permissions (see #213).
+* Improved `sitetreeload` command py3 compatibility (see #209).
+* Fixed `sitetreeload` unable to load some twisted tree structures (see #209).
+* Fixed `sitetree_resync_apps` run without args.
+* Fixed package distribution (see #222).
+
+
v1.6.0
------
+ Prevent TreeItems from being their own parents (see #200).
@@ -272,4 +284,4 @@ v0.1.1
v0.1.0
------
-+ Basic sitetree functionality.
++ Basic sitetree functionality.
\ No newline at end of file
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..ab641cf
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,31 @@
+django-sitetree installation
+============================
+
+
+Python ``pip`` package is required to install ``django-sitetree``.
+
+
+From sources
+------------
+
+Use the following command line to install ``django-sitetree`` from sources directory (containing setup.py):
+
+ pip install .
+
+or
+
+ python setup.py install
+
+
+From PyPI
+---------
+
+Alternatively you can install ``django-sitetree`` from PyPI:
+
+ pip install django-sitetree
+
+
+Use `-U` flag for upgrade:
+
+ pip install -U django-sitetree
+
diff --git a/MANIFEST.in b/MANIFEST.in
index 21ad930..715c48c 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -4,12 +4,12 @@ include LICENSE
include CHANGELOG
include docs/Makefile
-recursive-include docs .rst
-recursive-include docs .py
+recursive-include docs *.rst
+recursive-include docs *.py
recursive-include sitetree/locale *
-recursive-include sitetree/migrations .py
-recursive-include sitetree/south_migrations .py
-recursive-include sitetree/templates .html
-recursive-include sitetree/templatetags .py
-recursive-include sitetree/management .py
\ No newline at end of file
+recursive-include sitetree/migrations *.py
+recursive-include sitetree/south_migrations *.py
+recursive-include sitetree/templates *.html
+recursive-include sitetree/templatetags *.py
+recursive-include sitetree/management *.py
\ No newline at end of file
diff --git a/README.rst b/README.rst
index be98488..6cfaab0 100644
--- a/README.rst
+++ b/README.rst
@@ -2,23 +2,25 @@ django-sitetree
===============
http://github.com/idlesign/django-sitetree
-.. image:: https://img.shields.io/pypi/v/django-sitetree.svg
- :target: https://pypi.python.org/pypi/django-sitetree
+|release| |stats| |lic| |ci| |coverage| |health|
-.. image:: https://img.shields.io/pypi/dm/django-sitetree.svg
+.. |release| image:: https://img.shields.io/pypi/v/django-sitetree.svg
:target: https://pypi.python.org/pypi/django-sitetree
-.. image:: https://img.shields.io/pypi/l/django-sitetree.svg
+.. |stats| image:: https://img.shields.io/pypi/dm/django-sitetree.svg
:target: https://pypi.python.org/pypi/django-sitetree
-.. image:: https://img.shields.io/coveralls/idlesign/django-sitetree/master.svg
- :target: https://coveralls.io/r/idlesign/django-sitetree
+.. |lic| image:: https://img.shields.io/pypi/l/django-sitetree.svg
+ :target: https://pypi.python.org/pypi/django-sitetree
-.. image:: https://img.shields.io/travis/idlesign/django-sitetree/master.svg
+.. |ci| image:: https://img.shields.io/travis/idlesign/django-sitetree/master.svg
:target: https://travis-ci.org/idlesign/django-sitetree
-.. image:: https://landscape.io/github/idlesign/django-sitetree/master/landscape.svg?style=flat
- :target: https://landscape.io/github/idlesign/django-sitetree/master
+.. |coverage| image:: https://img.shields.io/coveralls/idlesign/django-sitetree/master.svg
+ :target: https://coveralls.io/r/idlesign/django-sitetree
+
+.. |health| image:: https://landscape.io/github/idlesign/django-sitetree/master/landscape.svg?style=flat
+ :target: https://landscape.io/github/idlesign/django-sitetree/master
What's that
diff --git a/docs/source/index.rst b/docs/source/index.rst
index 719f03a..b19d4ee 100644
--- a/docs/source/index.rst
+++ b/docs/source/index.rst
@@ -30,10 +30,9 @@ Requirements
------------
1. Python 2.6+, 3.3+
-2. Django 1.4.2+
+2. Django 1.7+
3. Auth Django contrib package
4. Admin site Django contrib package (optional)
-5. South 1.0+ (for automatic DB migrations; not required for Django 1.7+)
Table of Contents
diff --git a/docs/source/tags.rst b/docs/source/tags.rst
index df1797a..b85c49f 100644
--- a/docs/source/tags.rst
+++ b/docs/source/tags.rst
@@ -93,13 +93,17 @@ please use :ref:`tree hooks <tree-hooks>`.
Bad
Ugly
- + **this-ancestor-children** - items under grandparent item (closest to root) for the item resolved as current for the current page.
+ + **this-parent-siblings** - items under parent item for the item resolved as current for the current page.
Considering that we are now at `Public` renders::
Web
Postal
+ + **this-ancestor-children** - items under grandparent item (closest to root) for the item resolved as current for the current page.
+
+ Considering that we are now at `Public` renders all items under `Home` (which is closest to the root).
+
Thus in the template tag example above `trunk` is reserved alias, and `topmenu` alias is given to an item through
admin site.
diff --git a/setup.cfg b/setup.cfg
index 8b8c1dc..58cd3db 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,5 +1,6 @@
[aliases]
release = clean --all sdist bdist_wheel upload
+test = pytest
[wheel]
universal = 1
diff --git a/setup.py b/setup.py
index 9de2c87..507e68d 100755
--- a/setup.py
+++ b/setup.py
@@ -1,4 +1,5 @@
import os
+import sys
from setuptools import setup
from sitetree import VERSION
@@ -6,6 +7,8 @@ f = open(os.path.join(os.path.dirname(__file__), 'README.rst'))
readme = f.read()
f.close()
+PYTEST_RUNNER = ['pytest-runner'] if 'test' in sys.argv else []
+
setup(
name='django-sitetree',
version='.'.join(map(str, VERSION)),
@@ -22,6 +25,9 @@ setup(
include_package_data=True,
zip_safe=False,
+ setup_requires=[] + PYTEST_RUNNER,
+ tests_require=['pytest', 'pytest-django'],
+
classifiers=[
'Development Status :: 5 - Production/Stable',
'Environment :: Web Environment',
diff --git a/sitetree/__init__.py b/sitetree/__init__.py
index 2d28686..ae3dfcc 100644
--- a/sitetree/__init__.py
+++ b/sitetree/__init__.py
@@ -1,4 +1,4 @@
-VERSION = (1, 6, 0)
+VERSION = (1, 7, 0)
-default_app_config = 'sitetree.config.SitetreeConfig'
+default_app_config = 'sitetree.config.SitetreeConfig'
\ No newline at end of file
diff --git a/sitetree/fields.py b/sitetree/fields.py
index 05df777..f9fd3d9 100644
--- a/sitetree/fields.py
+++ b/sitetree/fields.py
@@ -6,6 +6,7 @@ from django.utils.safestring import mark_safe
from .templatetags.sitetree import sitetree_tree
from .utils import get_tree_model, get_tree_item_model
+from .settings import ITEMS_FIELD_ROOT_ID
MODEL_TREE_CLASS = get_tree_model()
@@ -40,23 +41,28 @@ class TreeItemChoiceField(ChoiceField):
tree_token = u'sitetree_tree from "%s" template "%s"' % (self.tree, self.template)
context_kwargs = {'current_app': 'admin'}
- if VERSION >= (1, 8):
- context = template.Context(context_kwargs)
- else:
- context = template.Context(**context_kwargs)
+ context = template.Context(context_kwargs) if VERSION >= (1, 8) else template.Context(**context_kwargs)
+ context.update({'request': object()})
choices_str = sitetree_tree(
Parser(None), Token(token_type=TOKEN_BLOCK, contents=tree_token)
).render(context)
- tree_choices = [('', self.root_title)]
+ tree_choices = [(ITEMS_FIELD_ROOT_ID, self.root_title)]
+
for line in choices_str.splitlines():
if line.strip():
splitted = line.split(':::')
tree_choices.append((splitted[0], mark_safe(splitted[1])))
+
return tree_choices
def clean(self, value):
if not value:
return None
- return MODEL_TREE_ITEM_CLASS.objects.get(pk=value)
+
+ try:
+ return MODEL_TREE_ITEM_CLASS.objects.get(pk=value)
+
+ except MODEL_TREE_ITEM_CLASS.DoesNotExist:
+ return None
diff --git a/sitetree/management/commands/sitetree_resync_apps.py b/sitetree/management/commands/sitetree_resync_apps.py
index 0a06135..129bb01 100644
--- a/sitetree/management/commands/sitetree_resync_apps.py
+++ b/sitetree/management/commands/sitetree_resync_apps.py
@@ -28,7 +28,7 @@ class Command(BaseCommand):
option_list = get_options()
def add_arguments(self, parser):
- parser.add_argument('args', metavar='app', nargs='+', help='Application names.')
+ parser.add_argument('args', metavar='app', nargs='*', help='Application names.')
get_options(parser.add_argument)
def handle(self, *apps, **options):
diff --git a/sitetree/management/commands/sitetreeload.py b/sitetree/management/commands/sitetreeload.py
index a90c089..68b0df4 100644
--- a/sitetree/management/commands/sitetreeload.py
+++ b/sitetree/management/commands/sitetreeload.py
@@ -30,7 +30,7 @@ get_options = options_getter((
help='Mode to put data into DB. Variants: `replace`, `append`.'),
CommandOption(
- '--items_into_tree', action='store', dest='into_tree', default=None,
+ '--items_into_tree', action='store', dest='items_into_tree', default=None,
help='Import only tree items data into tree with given alias.'),
))
@@ -50,7 +50,7 @@ class Command(BaseCommand):
using = options.get('database', DEFAULT_DB_ALIAS)
mode = options.get('mode', 'append')
- items_into_tree = options.get('into_tree', None)
+ items_into_tree = options.get('items_into_tree', None)
if items_into_tree is not None:
try:
@@ -78,11 +78,8 @@ class Command(BaseCommand):
loaded_object_count = 0
if mode == 'replace':
- try:
- MODEL_TREE_CLASS.objects.all().delete()
- MODEL_TREE_ITEM_CLASS.objects.all().delete()
- except ObjectDoesNotExist:
- pass
+ MODEL_TREE_CLASS.objects.all().delete()
+ MODEL_TREE_ITEM_CLASS.objects.all().delete()
for fixture_file in fixture_files:
@@ -137,6 +134,9 @@ class Command(BaseCommand):
parents_ahead = []
+ # Parents go first: enough for simple cases.
+ tree_items[orig_tree_id].sort(key=lambda item: item.id not in tree_item_parents.keys())
+
for tree_item in tree_items[orig_tree_id]:
parent_ahead = False
self.stdout.write('Importing item `%s` ...\n' % tree_item.title)
@@ -182,9 +182,7 @@ class Command(BaseCommand):
self.stderr.write(
self.style.ERROR('Fixture `%s` import error: %s\n' % (
- fixture_file, ''.join(traceback.format_exception(
- sys.exc_type, sys.exc_value, sys.exc_traceback
- ))
+ fixture_file, ''.join(traceback.format_exception(*sys.exc_info()))
))
)
diff --git a/sitetree/runtests.py b/sitetree/runtests.py
index 27970d5..be464ba 100755
--- a/sitetree/runtests.py
+++ b/sitetree/runtests.py
@@ -1,54 +1,5 @@
#! /usr/bin/env python
-import sys
-import os
-
-from django.conf import settings, global_settings
-
-
-APP_NAME = 'sitetree'
-
-
-def main():
- sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
-
- if not settings.configured:
-
- configure_kwargs = dict(
- INSTALLED_APPS=('django.contrib.auth', 'django.contrib.contenttypes', APP_NAME),
- DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3'}},
- ROOT_URLCONF='sitetree.tests',
- MIDDLEWARE_CLASSES=global_settings.MIDDLEWARE_CLASSES, # Prevents Django 1.7 warning.
- )
-
- try:
- configure_kwargs['TEMPLATE_CONTEXT_PROCESSORS'] = tuple(global_settings.TEMPLATE_CONTEXT_PROCESSORS) + (
- 'django.core.context_processors.request',
- )
-
- except AttributeError:
-
- # Django 1.8+
- configure_kwargs['TEMPLATES'] = [
- {
- 'BACKEND': 'django.template.backends.django.DjangoTemplates',
- 'APP_DIRS': True,
- },
- ]
-
- settings.configure(**configure_kwargs)
-
- try: # Django 1.7 +
- from django import setup
- setup()
- except ImportError:
- pass
-
- from django.test.utils import get_runner
- runner = get_runner(settings)()
- failures = runner.run_tests((APP_NAME,))
-
- sys.exit(failures)
-
if __name__ == '__main__':
- main()
+ from pytest import main as pytest_main
+ pytest_main()
diff --git a/sitetree/settings.py b/sitetree/settings.py
index 218bde5..492c559 100644
--- a/sitetree/settings.py
+++ b/sitetree/settings.py
@@ -2,17 +2,30 @@ from django.conf import settings
MODEL_TREE = getattr(settings, 'SITETREE_MODEL_TREE', 'sitetree.Tree')
+"""Path to a tree model (app.class)."""
+
MODEL_TREE_ITEM = getattr(settings, 'SITETREE_MODEL_TREE_ITEM', 'sitetree.TreeItem')
+"""Path to a tree item model (app.class)."""
APP_MODULE_NAME = getattr(settings, 'SITETREE_APP_MODULE_NAME', 'sitetrees')
+"""Module name where applications store trees shipped with them."""
UNRESOLVED_ITEM_MARKER = getattr(settings, 'SITETREE_UNRESOLVED_ITEM_MARKER', u'#unresolved')
+"""This string is place instead of item URL if actual URL cannot be resolved."""
RAISE_ITEMS_ERRORS_ON_DEBUG = getattr(settings, 'SITETREE_RAISE_ITEMS_ERRORS_ON_DEBUG', True)
-# Sitetree objects are stored in Django cache for a year (60 * 60 * 24 * 365 = 31536000 sec).
-# Cache is only invalidated on sitetree or sitetree item change.
+ITEMS_FIELD_ROOT_ID = getattr(settings, 'SITETREE_ITEMS_FIELD_ROOT_ID', '')
+"""Item ID to be used for root item in TreeItemChoiceField.
+This is adjustable to be able to workaround client-side field validation issues in thirdparties.
+
+"""
+
CACHE_TIMEOUT = getattr(settings, 'SITETREE_CACHE_TIMEOUT', 31536000)
+"""Sitetree objects are stored in Django cache for a year (60 * 60 * 24 * 365 = 31536000 sec).
+Cache is only invalidated on sitetree or sitetree item change.
+
+"""
# Reserved tree items aliases.
ALIAS_TRUNK = 'trunk'
diff --git a/sitetree/sitetreeapp.py b/sitetree/sitetreeapp.py
index e387106..90e9e95 100644
--- a/sitetree/sitetreeapp.py
+++ b/sitetree/sitetreeapp.py
@@ -1,9 +1,7 @@
from __future__ import unicode_literals
-
import warnings
-
from collections import defaultdict
-from copy import copy, deepcopy
+from copy import deepcopy
from threading import local
from functools import partial
@@ -15,7 +13,6 @@ from django.utils import six
from django.utils.http import urlquote
from django.utils.translation import get_language
from django.utils.encoding import python_2_unicode_compatible
-from django.template import Context
from django.template.loader import get_template
from django.template.base import (
FilterExpression, Lexer, Parser, Token, Variable, VariableDoesNotExist, TOKEN_BLOCK, UNKNOWN_SOURCE, TOKEN_TEXT,
@@ -29,6 +26,11 @@ from .settings import (
from .exceptions import SiteTreeError
+if False: # For type hinting purposes.
+ from django.template import Context
+ from .models import TreeItemBase
+
+
if VERSION >= (1, 9, 0):
get_lexer = partial(Lexer)
else:
@@ -39,36 +41,44 @@ MODEL_TREE_CLASS = get_tree_model()
MODEL_TREE_ITEM_CLASS = get_tree_item_model()
-# Holds tree items processor callable or None.
_ITEMS_PROCESSOR = None
-# Holds aliases of trees that support internationalization.
+"""Stores tree items processor callable or None."""
+
_I18N_TREES = []
-# Holds trees dynamically loaded from project apps.
+"""Stores aliases of trees supporting internationalization."""
+
_DYNAMIC_TREES = {}
-# Dictionary index in `_DYNAMIC_TREES` for orphaned trees list.
+"""Holds trees dynamically loaded from project apps."""
+
_IDX_ORPHAN_TREES = 'orphans'
-# Dictinary index name template in `_DYNAMIC_TREES`.
+"""Dictionary index in `_DYNAMIC_TREES` for orphaned trees list."""
+
_IDX_TPL = '%s|:|%s'
-# SiteTree app-wise object.
-_SITETREE = None
+"""Name template used as dictionary index in `_DYNAMIC_TREES`."""
_THREAD_LOCAL = local()
-_THREAD_LANG = 'sitetree_lang'
-_THREAD_CACHE = 'sitetree_cache'
+_THREAD_SITETREE = 'sitetree'
+
+_URL_TAG_NEW_STYLE = VERSION >= (1, 5, 0)
+
+_UNSET = set() # Sentinel
def get_sitetree():
- """Returns SiteTree [singleton] object, implementing utility methods.
+ """Returns SiteTree (thread-singleton) object, implementing utility methods.
- :return: SiteTree
+ :rtype: SiteTree
"""
- global _SITETREE
- if _SITETREE is None:
- _SITETREE = SiteTree()
- return _SITETREE
+ sitetree = getattr(_THREAD_LOCAL, _THREAD_SITETREE, None)
+
+ if sitetree is None:
+ sitetree = SiteTree()
+ setattr(_THREAD_LOCAL, _THREAD_SITETREE, sitetree)
+
+ return sitetree
-def register_items_hook(callable):
+def register_items_hook(func):
"""Registers a hook callable to process tree items right before they are passed to templates.
Callable should be able to:
@@ -101,9 +111,10 @@ def register_items_hook(callable):
# And we register items processor.
register_items_hook(my_items_processor)
+ :param func:
"""
global _ITEMS_PROCESSOR
- _ITEMS_PROCESSOR = callable
+ _ITEMS_PROCESSOR = func
def register_i18n_trees(aliases):
@@ -129,6 +140,7 @@ def register_i18n_trees(aliases):
# At last we register i18n trees.
register_i18n_trees(['my_tree', 'my_another_tree'])
+ :param aliases:
"""
global _I18N_TREES
_I18N_TREES = aliases
@@ -163,10 +175,9 @@ def register_dynamic_trees(trees, *args, **kwargs):
)
Accepted kwargs:
+ bool reset_cache: Resets tree cache, to introduce all changes made to a tree immediately.
- :param bool reset_cache: Resets tree cache, to introduce all changes made to a tree immediately.
"""
-
global _DYNAMIC_TREES
if _IDX_ORPHAN_TREES not in _DYNAMIC_TREES:
@@ -193,9 +204,9 @@ def register_dynamic_trees(trees, *args, **kwargs):
reset_cache = kwargs.get('reset_cache', False)
if reset_cache:
- cache = get_sitetree().cache
- cache.empty()
- cache.reset()
+ cache_ = get_sitetree().cache
+ cache_.empty()
+ cache_.reset()
def get_dynamic_trees():
@@ -207,38 +218,40 @@ def compose_dynamic_tree(src, target_tree_alias=None, parent_tree_item_alias=Non
"""Returns a structure describing a dynamic sitetree.utils
The structure can be built from various sources,
- Thus, if a string is passed to `src`, it'll be treated as the name of an app,
- from where one want to import sitetrees definitions.
-
- On the other hand, `src` can be an iterable of trees definitions
- (see `sitetree.utils.tree()` and `item()` functions).
+ :param str|iterable src: If a string is passed to `src`, it'll be treated as the name of an app,
+ from where one want to import sitetrees definitions. `src` can be an iterable
+ of tree definitions (see `sitetree.toolbox.tree()` and `item()` functions).
+ :param str|unicode target_tree_alias: Static tree alias to attach items from dynamic trees to.
- `target_tree_alias` - expects a static tree alias to attach items from dynamic trees to.
- `parent_tree_item_alias` - expects a tree item alias from a static tree to attach items from dynamic trees to.
- `include_trees` - expects a list of sitetree aliases to filter `src`.
+ :param str|unicode parent_tree_item_alias: Tree item alias from a static tree to attach items from dynamic trees to.
+ :param list include_trees: Sitetree aliases to filter `src`.
+ :rtype: dict
"""
-
def result(sitetrees=src):
if include_trees is not None:
sitetrees = [tree for tree in sitetrees if tree.alias in include_trees]
- return {'app': src, 'sitetrees': sitetrees, 'tree': target_tree_alias, 'parent_item': parent_tree_item_alias}
+
+ return {
+ 'app': src,
+ 'sitetrees': sitetrees,
+ 'tree': target_tree_alias,
+ 'parent_item': parent_tree_item_alias}
if isinstance(src, six.string_types):
- # Considered an application name.
+ # Considered to be an application name.
try:
module = import_app_sitetree_module(src)
- if module is None:
- return None
- return result(getattr(module, 'sitetrees', None))
+ return None if module is None else result(getattr(module, 'sitetrees', None))
+
except ImportError as e:
if settings.DEBUG:
warnings.warn('Unable to register dynamic sitetree(s) for `%s` application: %s. ' % (src, e))
- else:
- return result()
- return None
+ return None
+
+ return result()
@python_2_unicode_compatible
@@ -247,6 +260,9 @@ class LazyTitle(object):
Produces resolved title as unicode representation."""
def __init__(self, title):
+ """
+ :param str|unicode title:
+ """
self.title = title
def __str__(self):
@@ -259,7 +275,7 @@ class LazyTitle(object):
my_tokens.remove(my_token)
my_parser = Parser(my_tokens)
- return my_parser.parse().render(SiteTree.get_global_context())
+ return my_parser.parse().render(get_sitetree().current_page_context)
def __eq__(self, other):
return self.__str__() == other
@@ -278,6 +294,7 @@ class Cache(object):
signals.post_delete.connect(cache_empty, sender=MODEL_TREE_ITEM_CLASS)
# Listen to the changes in item permissions table.
signals.m2m_changed.connect(cache_empty, sender=MODEL_TREE_ITEM_CLASS.access_permissions)
+ self.init()
@classmethod
def reset(cls):
@@ -292,18 +309,10 @@ class Cache(object):
"""Initializes local cache from Django cache."""
# Drop cache flag set by .reset() method.
- cache.get('sitetrees_reset') and self.empty()
-
- cache_ = getattr(_THREAD_LOCAL, _THREAD_CACHE, None)
- if cache_ is None:
-
- cache_ = cache.get(
- # Init cache dictionary with predefined entries.
- 'sitetrees', {'sitetrees': {}, 'urls': {}, 'parents': {}, 'items_by_ids': {}, 'tree_aliases': {}})
+ cache.get('sitetrees_reset') and self.empty(init=False)
- setattr(_THREAD_LOCAL, _THREAD_CACHE, cache_)
-
- self.cache = cache_
+ self.cache = cache.get(
+ 'sitetrees', {'sitetrees': {}, 'parents': {}, 'items_by_ids': {}, 'tree_aliases': {}})
def save(self):
"""Saves sitetree data to Django cache."""
@@ -311,61 +320,85 @@ class Cache(object):
def empty(self, **kwargs):
"""Empties cached sitetree data."""
- self.cache = None
- setattr(_THREAD_LOCAL, _THREAD_CACHE, None)
cache.delete('sitetrees')
cache.delete('sitetrees_reset')
+ kwargs.get('init', True) and self.init()
+
def get_entry(self, entry_name, key):
- """Returns cache entry parameter value by its name."""
+ """Returns cache entry parameter value by its name.
+
+ :param str|unicode entry_name:
+ :param key:
+ :return:
+ """
return self.cache[entry_name].get(key, False)
def update_entry_value(self, entry_name, key, value):
- """Updates cache entry parameter with new data."""
+ """Updates cache entry parameter with new data.
+
+ :param str|unicode entry_name:
+ :param key:
+ :param value:
+ """
if key not in self.cache[entry_name]:
self.cache[entry_name][key] = {}
+
self.cache[entry_name][key].update(value)
def set_entry(self, entry_name, key, value):
- """Replaces entire cache entry parameter data by its name with new data."""
+ """Replaces entire cache entry parameter data by its name with new data.
+
+ :param str|unicode entry_name:
+ :param key:
+ :param value:
+ """
self.cache[entry_name][key] = value
class SiteTree(object):
-
- _global_context = Context()
+ """Main logic handler."""
def __init__(self):
- self.cache = Cache()
+ self.init(context=None)
- @classmethod
- def set_global_context(cls, context):
- """Saves context as global context if not already set or if changed.
- Almost all variables are resolved against global context.
+ def init(self, context):
+ """Initializes sitetree to handle new request.
+ :param Context|None context:
"""
- if not cls._global_context or id(context) != id(cls._global_context):
- cls._global_context = context
+ self.cache = Cache()
+ self.current_page_context = context
+ self.current_request = context.get('request', None) if context else None
+ self.current_lang = get_language()
- @classmethod
- def get_global_context(cls):
- """Returns current sitetree global context."""
- return cls._global_context
+ self._current_app_is_admin = None
+ self._current_user_permissions = _UNSET
+ self._items_urls = {} # Resolved urls are cache for a request.
+ self._current_items = {}
def resolve_tree_i18n_alias(self, alias):
"""Resolves internationalized tree alias.
Verifies whether a separate sitetree is available for currently active language.
If so, returns i18n alias. If not, returns the initial alias.
+
+ :param str|unicode alias:
+ :rtype: str|unicode
"""
- if alias in _I18N_TREES:
- current_language_code = self.lang_get().replace('_', '-').split('-')[0]
- i18n_tree_alias = '%s_%s' % (alias, current_language_code)
- trees_count = self.cache.get_entry('tree_aliases', i18n_tree_alias)
- if trees_count is False:
- trees_count = MODEL_TREE_CLASS.objects.filter(alias=i18n_tree_alias).count()
- self.cache.set_entry('tree_aliases', i18n_tree_alias, trees_count)
- if trees_count:
- alias = i18n_tree_alias
+ if alias not in _I18N_TREES:
+ return alias
+
+ current_language_code = self.current_lang.replace('_', '-').split('-')[0]
+ i18n_tree_alias = '%s_%s' % (alias, current_language_code)
+ trees_count = self.cache.get_entry('tree_aliases', i18n_tree_alias)
+
+ if trees_count is False:
+ trees_count = MODEL_TREE_CLASS.objects.filter(alias=i18n_tree_alias).count()
+ self.cache.set_entry('tree_aliases', i18n_tree_alias, trees_count)
+
+ if trees_count:
+ alias = i18n_tree_alias
+
return alias
@staticmethod
@@ -373,18 +406,21 @@ class SiteTree(object):
"""Attaches dynamic sitetrees items registered with `register_dynamic_trees()`
to an initial (source) items list.
+ :param str|unicode tree_alias:
+ :param list src_tree_items:
+ :rtype: list
"""
if not _DYNAMIC_TREES:
return src_tree_items
# This guarantees that a dynamic source stays intact,
# no matter how dynamic sitetrees are attached.
- TREES = deepcopy(_DYNAMIC_TREES)
+ trees = deepcopy(_DYNAMIC_TREES)
items = []
if not src_tree_items:
- if _IDX_ORPHAN_TREES in TREES and tree_alias in TREES[_IDX_ORPHAN_TREES]:
- for tree in TREES[_IDX_ORPHAN_TREES][tree_alias]:
+ if _IDX_ORPHAN_TREES in trees and tree_alias in trees[_IDX_ORPHAN_TREES]:
+ for tree in trees[_IDX_ORPHAN_TREES][tree_alias]:
items.extend(tree.dynamic_items)
else:
@@ -393,67 +429,87 @@ class SiteTree(object):
# Tree item attachment by alias.
for static_item in list(src_tree_items):
items.append(static_item)
- if static_item.alias:
- idx = _IDX_TPL % (tree_alias, static_item.alias)
- if idx in TREES:
- for tree in TREES[idx]:
- tree.alias = tree_alias
- for dyn_item in tree.dynamic_items:
- if dyn_item.parent is None:
- dyn_item.parent = static_item
- # Unique IDs are required for the same trees attached
- # to different parents.
- dyn_item.id = generate_id_for(dyn_item)
- items.append(dyn_item)
+ if not static_item.alias:
+ continue
+
+ idx = _IDX_TPL % (tree_alias, static_item.alias)
+ if idx not in trees:
+ continue
+
+ for tree in trees[idx]:
+ tree.alias = tree_alias
+ for dyn_item in tree.dynamic_items:
+ if dyn_item.parent is None:
+ dyn_item.parent = static_item
+ # Unique IDs are required for the same trees attached
+ # to different parents.
+ dyn_item.id = generate_id_for(dyn_item)
+ items.append(dyn_item)
# Tree root attachment.
idx = _IDX_TPL % (tree_alias, None)
if idx in _DYNAMIC_TREES:
- TREES = deepcopy(_DYNAMIC_TREES)
- for tree in TREES[idx]:
+ trees = deepcopy(_DYNAMIC_TREES)
+ for tree in trees[idx]:
tree.alias = tree_alias
items.extend(tree.dynamic_items)
return items
def current_app_is_admin(self):
- """Returns boolean whether current application is Admin contrib."""
- global_context = self._global_context
+ """Returns boolean whether current application is Admin contrib.
+
+ :rtype: bool
+ """
+ is_admin = self._current_app_is_admin
+ if is_admin is None:
+ context = self.current_page_context
+
+ current_app = getattr(
+ # Try from request.resolver_match.app_name
+ getattr(context.get('request', None), 'resolver_match', None), 'app_name',
+ # Try from global context obj.
+ getattr(context, 'current_app', None))
- current_app = getattr(
- # Try from request.resolver_match.app_name
- getattr(global_context.get('request', None), 'resolver_match', None), 'app_name',
- # Try from global context obj.
- getattr(global_context, 'current_app', None))
+ if current_app is None: # Try from global context dict.
+ current_app = context.get('current_app', '')
- if current_app is None: # Try from global context dict.
... 3210 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/django-sitetree.git
More information about the Python-modules-commits
mailing list