Skip to content

Commit

Permalink
Add __self__ and __func__ for bound templates. Fixes #3
Browse files Browse the repository at this point in the history
  • Loading branch information
jamadden committed Oct 17, 2017
1 parent 5c39616 commit dc67b36
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 10 deletions.
6 changes: 5 additions & 1 deletion CHANGES.rst
Expand Up @@ -8,12 +8,16 @@
- Add support for PyPy.
- Add support for Python 3.4, 3.5 and 3.6.
- Drop support for Python 2.6 and 3.3.
- Make bound page templates have ``__self__`` and ``__func__``
attributes to be more like Python 3 bound methods. (``im_func`` and
``im_self`` remain available.) See `issue 3
<https://github.com/zopefoundation/z3c.template/issues/3>`_.


2.0.0 (2015-11-09)
==================

- Standardize namespace __init__
- Standardize namespace ``__init__``


2.0.0a2 (2013-02-25)
Expand Down
23 changes: 15 additions & 8 deletions src/z3c/template/template.py
Expand Up @@ -12,7 +12,7 @@
#
##############################################################################
"""
$Id$
Implementation of templates.
"""

from zope import component
Expand All @@ -28,7 +28,7 @@ class Macro(object):
# because it (obviously) only supports the Zope page template
# implementation. As a workaround or trick we use a wrapper
# template.

wrapper = PageTemplate()
wrapper.write(
'<metal:main use-macro="python: options[\'macro\']" />'
Expand Down Expand Up @@ -72,22 +72,29 @@ def __call__(self, view, request, context=None):


class BoundViewTemplate(object):
__self__ = None
__func__ = None

def __init__(self, pt, ob):
object.__setattr__(self, 'im_func', pt)
object.__setattr__(self, 'im_self', ob)
object.__setattr__(self, '__func__', pt)
object.__setattr__(self, '__self__', ob)

im_self = property(lambda self: self.__self__)
im_func = property(lambda self: self.__func__)


def __call__(self, *args, **kw):
if self.im_self is None:
if self.__self__ is None:
im_self, args = args[0], args[1:]
else:
im_self = self.im_self
return self.im_func(im_self, *args, **kw)
im_self = self.__self__
return self.__func__(im_self, *args, **kw)

def __setattr__(self, name, v):
raise AttributeError("Can't set attribute", name)

def __repr__(self):
return "<BoundViewTemplate of %r>" % self.im_self
return "<BoundViewTemplate of %r>" % self.__self__


class ViewTemplate(object):
Expand Down
11 changes: 10 additions & 1 deletion src/z3c/template/tests.py
Expand Up @@ -87,7 +87,7 @@ def __init__(self):

class TestBoundViewTemplate(unittest.TestCase):

def test_call_no_im_self_uses_first_arg(self):
def test_call_no__self__uses_first_arg(self):
def im_func(*args):
return args
bound = z3c.template.template.BoundViewTemplate(im_func, None)
Expand All @@ -108,6 +108,15 @@ def test_repr(self):
self.assertEqual("<BoundViewTemplate of 'im_self'>",
repr(bound))

def test_attributes(self):
func = object()
bound = z3c.template.template.BoundViewTemplate(func, self)
self.assertIs(self, bound.im_self)
self.assertIs(self, bound.__self__)
self.assertIs(func, bound.im_func)
self.assertIs(func, bound.__func__)


def test_suite():
setups = (setUpZPT, setUpZ3CPT)
doctests = ((
Expand Down

0 comments on commit dc67b36

Please sign in to comment.