diff --git a/.gitignore b/.gitignore index 0efe71c2..4e429af1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ .DS_Store +.venv* +.idea/** *.pyc dist build diff --git a/README.md b/README.md index 46860bbc..31374934 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,3 @@ -[![Build Status](https://travis-ci.org/eudicots/Cactus.svg?branch=master)](https://travis-ci.org/eudicots/Cactus) - -News --------------- ### Cactus 3 is out! diff --git a/cactus/deployment/__init__.py b/cactus/deployment/__init__.py index ea41799b..500272d7 100644 --- a/cactus/deployment/__init__.py +++ b/cactus/deployment/__init__.py @@ -32,7 +32,8 @@ def get_deployment_engine_class(provider): _mod = __import__(module, fromlist=[engine]) except ImportError as e: logger.error("Unable to import requested engine (%s) for provider %s", engine, provider) - logger.error("A required library was missing: %s", e.message) + logger.error("A required library was missing: %s", str(e)) logger.error("Please install the library and try again") + raise e else: return getattr(_mod, engine) diff --git a/cactus/i18n/commands.py b/cactus/i18n/commands.py index 0a67db18..c680ac73 100644 --- a/cactus/i18n/commands.py +++ b/cactus/i18n/commands.py @@ -12,6 +12,9 @@ "pythonpath": None, "traceback": True, "all": False, + "no_color": False, + "exclude": [], + "fuzzy": False, } DEFAULT_MAKEMESSAGES_KWARGS = { diff --git a/cactus/site.py b/cactus/site.py index beacc92f..51ba3351 100644 --- a/cactus/site.py +++ b/cactus/site.py @@ -6,7 +6,7 @@ import traceback import socket -import django.conf +from django import conf as django_conf from cactus import ui as ui_module from cactus.config.router import ConfigRouter @@ -142,10 +142,30 @@ def setup(self): Configure django to use both our template and pages folder as locations to look for included templates. """ - settings = { - "TEMPLATE_DIRS": [self.template_path, self.page_path], "INSTALLED_APPS": ['django_markwhat'], + "TEMPLATES": [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [self.template_path, self.page_path], + 'APP_DIRS': False, + 'OPTIONS': { + 'context_processors': [ + # list of default context processors in Django 1.6 + "django.contrib.auth.context_processors.auth", + "django.template.context_processors.debug", + "django.template.context_processors.i18n", + "django.template.context_processors.media", + "django.template.context_processors.static", + "django.template.context_processors.tz", + "django.contrib.messages.context_processors.messages" + ], + 'builtins': [ + 'cactus.template_tags' + ], + } + } + ] } if self.locale is not None: @@ -156,13 +176,12 @@ def setup(self): "LOCALE_PATHS": [self.locale_path], }) - django.conf.settings.configure(**settings) + django_conf.settings.configure(**settings) + + import django + django.setup() + - # - Importing here instead of the top-level makes it work on Python 3.x (!) - # - loading add_to_builtins from loader implictly loads the loader_tags built-in - # - Injecting our tags using add_to_builtins ensures that Cactus tags don't require an import - from django.template.loader import add_to_builtins - add_to_builtins('cactus.template_tags') def verify_path(self): """ diff --git a/cactus/template_tags.py b/cactus/template_tags.py index f5b46d51..bba06cd5 100644 --- a/cactus/template_tags.py +++ b/cactus/template_tags.py @@ -2,14 +2,13 @@ import os import logging -from django.template.base import Library -from django.conf import settings +from django import template from django.utils.encoding import force_text from django.utils.safestring import mark_safe logger = logging.getLogger(__name__) -register = Library() +register = template.Library() def static(context, link_url): diff --git a/cactus/utils/inspect23.py b/cactus/utils/inspect23.py new file mode 100644 index 00000000..e9e43f69 --- /dev/null +++ b/cactus/utils/inspect23.py @@ -0,0 +1,89 @@ +""" +Python2/3 compatible version of inspect. +Source: https://github.com/timgraham/django/blob/3872a33132a4bb6aa22b237927597bbfdf6f21d7/django/utils/inspect.py + +Slightly modified so getargspec() always returns a named tuple (ArgSpec). +""" + +from __future__ import absolute_import + +import inspect +import six +from collections import namedtuple + +ArgSpec = namedtuple('ArgSpec', 'args varargs keywords defaults') + + +def getargspec(func): + if six.PY2: + return inspect.getargspec(func) + + sig = inspect.signature(func) + args = [ + p.name for p in sig.parameters.values() + if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD + ] + varargs = [ + p.name for p in sig.parameters.values() + if p.kind == inspect.Parameter.VAR_POSITIONAL + ] + varargs = varargs[0] if varargs else None + varkw = [ + p.name for p in sig.parameters.values() + if p.kind == inspect.Parameter.VAR_KEYWORD + ] + varkw = varkw[0] if varkw else None + defaults = [ + p.default for p in sig.parameters.values() + if p.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD and p.default is not p.empty + ] or None + return ArgSpec(args, varargs, varkw, defaults) + + +def get_func_args(func): + if six.PY2: + argspec = inspect.getargspec(func) + return argspec.args[1:] # ignore 'self' + + sig = inspect.signature(func) + return [ + arg_name for arg_name, param in sig.parameters.items() + if param.kind == inspect.Parameter.POSITIONAL_OR_KEYWORD + ] + + +def func_accepts_kwargs(func): + if six.PY2: + # Not all callables are inspectable with getargspec, so we'll + # try a couple different ways but in the end fall back on assuming + # it is -- we don't want to prevent registration of valid but weird + # callables. + try: + argspec = inspect.getargspec(func) + except TypeError: + try: + argspec = inspect.getargspec(func.__call__) + except (TypeError, AttributeError): + argspec = None + return not argspec or argspec[2] is not None + + return any( + p for p in inspect.signature(func).parameters.values() + if p.kind == p.VAR_KEYWORD + ) + + +def func_has_no_args(func): + args = inspect.getargspec(func)[0] if six.PY2 else [ + p for p in inspect.signature(func).parameters.values() + if p.kind == p.POSITIONAL_OR_KEYWORD and p.default is p.empty + ] + return len(args) == 1 + + +def func_supports_parameter(func, parameter): + if six.PY3: + return parameter in inspect.signature(func).parameters + else: + args, varargs, varkw, defaults = inspect.getargspec(func) + return parameter in args \ No newline at end of file diff --git a/cactus/utils/internal.py b/cactus/utils/internal.py index 9b507af5..d2f996b8 100644 --- a/cactus/utils/internal.py +++ b/cactus/utils/internal.py @@ -1,6 +1,7 @@ #coding:utf-8 import six import inspect +from .inspect23 import getargspec as six_getargspec # Adapted from: http://kbyanc.blogspot.com/2007/07/python-more-generic-getargspec.html @@ -33,16 +34,16 @@ def getargspec(obj): raise TypeError("%s is not callable" % type(obj)) try: if inspect.isfunction(obj): - return inspect.getargspec(obj) + return six_getargspec(obj) elif hasattr(obj, FUNC_OBJ_ATTR): # For methods or classmethods drop the first # argument from the returned list because # python supplies that automatically for us. # Note that this differs from what - # inspect.getargspec() returns for methods. + # six_getargspec()() returns for methods. # NB: We use im_func so we work with # instancemethod objects also. - spec = inspect.getargspec(getattr(obj, FUNC_OBJ_ATTR)) + spec = six_getargspec(getattr(obj, FUNC_OBJ_ATTR)) return inspect.ArgSpec(spec.args[:1], spec.varargs, spec.keywords, spec.defaults) elif inspect.isclass(obj): return getargspec(obj.__init__) diff --git a/requirements.txt b/requirements.txt index 3116e4b7..37fae6f9 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -Django>=1.6,<1.7 +Django==1.11.29 django-markwhat>=1.4,<2 markdown2 argparse diff --git a/run.py b/run.py index de31e5bf..653634b0 100755 --- a/run.py +++ b/run.py @@ -1,11 +1,11 @@ #!/usr/bin/env python # encoding: utf-8 - +import sys import cactus from cactus.cli import main -print "Using: %s" % cactus.__file__ +print("Using: %s" % cactus.__file__) if __name__ == "__main__": - main() \ No newline at end of file + main(sys.argv[1:])