import os import os.path import sys import shutil import tempfile import unittest from Cheetah.Template import Template from Cheetah.compat import unicode class TemplateTest(unittest.TestCase): pass class ClassMethods_compile(TemplateTest): """I am using the same Cheetah source for each test to root out clashes caused by the compile caching in Template.compile(). """ def test_basicUsage(self): klass = Template.compile(source='$foo') t = klass(namespaces={'foo': 1234}) assert str(t) == '1234' def test_baseclassArg(self): klass = Template.compile(source='$foo', baseclass=dict) t = klass({'foo': 1234}) assert str(t) == '1234' klass2 = Template.compile(source='$foo', baseclass=klass) t = klass2({'foo': 1234}) assert str(t) == '1234' klass3 = Template.compile(source='#implements dummy\n$bar', baseclass=klass2) t = klass3({'foo': 1234}) assert str(t) == '1234' klass4 = Template.compile(source='$foo', baseclass='dict') t = klass4({'foo': 1234}) assert str(t) == '1234' def test_moduleFileCaching(self): tmpDir = tempfile.mkdtemp() try: # print tmpDir assert os.path.exists(tmpDir) klass = Template.compile(source='$foo', cacheModuleFilesForTracebacks=True, cacheDirForModuleFiles=tmpDir) mod = sys.modules[klass.__module__] # print mod.__file__ assert os.path.exists(mod.__file__) assert os.path.dirname(mod.__file__) == tmpDir finally: shutil.rmtree(tmpDir, True) def test_classNameArg(self): klass = Template.compile(source='$foo', className='foo123') assert klass.__name__ == 'foo123' t = klass(namespaces={'foo': 1234}) assert str(t) == '1234' def test_moduleNameArg(self): klass = Template.compile(source='$foo', moduleName='foo99') assert klass.__name__ == 'foo99' t = klass(namespaces={'foo': 1234}) assert str(t) == '1234' klass = Template.compile(source='$foo', moduleName='foo1', className='foo2') assert klass.__name__ == 'foo2' t = klass(namespaces={'foo': 1234}) assert str(t) == '1234' def test_mainMethodNameArg(self): klass = Template.compile(source='$foo', className='foo123', mainMethodName='testMeth') assert klass.__name__ == 'foo123' t = klass(namespaces={'foo': 1234}) # print t.generatedClassCode() assert str(t) == '1234' assert t.testMeth() == '1234' klass = Template.compile(source='$foo', moduleName='fooXXX', className='foo123', mainMethodName='testMeth', baseclass=dict) assert klass.__name__ == 'foo123' t = klass({'foo': 1234}) # print t.generatedClassCode() assert str(t) == '1234' assert t.testMeth() == '1234' def test_moduleGlobalsArg(self): klass = Template.compile(source='$foo', moduleGlobals={'foo': 1234}) t = klass() assert str(t) == '1234' klass2 = Template.compile(source='$foo', baseclass='Test1', moduleGlobals={'Test1': dict}) t = klass2({'foo': 1234}) assert str(t) == '1234' klass3 = Template.compile(source='$foo', baseclass='Test1', moduleGlobals={'Test1': dict, 'foo': 1234}) t = klass3() assert str(t) == '1234' def test_keepRefToGeneratedCodeArg(self): klass = Template.compile(source='$foo', className='unique58', cacheCompilationResults=False, keepRefToGeneratedCode=False) t = klass(namespaces={'foo': 1234}) assert str(t) == '1234' assert not t.generatedModuleCode() klass2 = Template.compile(source='$foo', className='unique58', keepRefToGeneratedCode=True) t = klass2(namespaces={'foo': 1234}) assert str(t) == '1234' assert t.generatedModuleCode() klass3 = Template.compile(source='$foo', className='unique58', keepRefToGeneratedCode=False) t = klass3(namespaces={'foo': 1234}) assert str(t) == '1234' # still there as this class came from the cache assert t.generatedModuleCode() def test_compilationCache(self): klass = Template.compile(source='$foo', className='unique111', cacheCompilationResults=False) t = klass(namespaces={'foo': 1234}) assert str(t) == '1234' assert not klass._CHEETAH_isInCompilationCache # this time it will place it in the cache klass = Template.compile(source='$foo', className='unique111', cacheCompilationResults=True) t = klass(namespaces={'foo': 1234}) assert str(t) == '1234' assert klass._CHEETAH_isInCompilationCache # by default it will be in the cache klass = Template.compile(source='$foo', className='unique999099') t = klass(namespaces={'foo': 1234}) assert str(t) == '1234' assert klass._CHEETAH_isInCompilationCache class ClassMethods_subclass(TemplateTest): def test_basicUsage(self): klass = Template.compile(source='$foo', baseclass=dict) t = klass({'foo': 1234}) assert str(t) == '1234' klass2 = klass.subclass(source='$foo') t = klass2({'foo': 1234}) assert str(t) == '1234' klass3 = klass2.subclass(source='#implements dummy\n$bar') t = klass3({'foo': 1234}) assert str(t) == '1234' class Preprocessors(TemplateTest): def test_basicUsage1(self): src = '''\ %set foo = @a $(@foo*10) @a''' src = '\n'.join([ln.strip() for ln in src.splitlines()]) preprocessors = {'tokens': '@ %', 'namespaces': {'a': 99} } klass = Template.compile(src, preprocessors=preprocessors) assert str(klass()) == '990\n99' def test_normalizePreprocessorArgVariants(self): src = '%set foo = 12\n%%comment\n$(@foo*10)' class Settings1: tokens = '@ %' Settings1 = Settings1() from Cheetah.Template import TemplatePreprocessor settings = Template._normalizePreprocessorSettings(Settings1) preprocObj = TemplatePreprocessor(settings) def preprocFunc(source, file): return '$(12*10)', None class TemplateSubclass(Template): pass compilerSettings = {'cheetahVarStartToken': '@', 'directiveStartToken': '%', 'commentStartToken': '%%', } for arg in ['@ %', {'tokens': '@ %'}, {'compilerSettings': compilerSettings}, {'compilerSettings': compilerSettings, 'templateInitArgs': {}}, {'tokens': '@ %', 'templateAPIClass': TemplateSubclass}, Settings1, preprocObj, preprocFunc, ]: klass = Template.compile(src, preprocessors=arg) assert str(klass()) == '120' def test_complexUsage(self): src = '''\ %set foo = @a %def func1: #def func(arg): $arg("***") %% comment $(@foo*10) @func1 $func(lambda x:c"--$x--@a")''' src = '\n'.join([ln.strip() for ln in src.splitlines()]) for arg in [{'tokens': '@ %', 'namespaces': {'a': 99}}, {'tokens': '@ %', 'namespaces': {'a': 99}}, ]: klass = Template.compile(src, preprocessors=arg) t = klass() assert str(t) == '990\n--***--99' def test_i18n(self): src = '''\ %i18n: This is a $string that needs translation %i18n id="foo", domain="root": This is a $string that needs translation ''' src = '\n'.join([ln.strip() for ln in src.splitlines()]) klass = Template.compile(src, preprocessors='@ %', baseclass=dict) t = klass({'string': 'bit of text'}) # print str(t), repr(str(t)) assert str(t) == ( 'This is a bit of text that needs translation\n'*2)[:-1] # noqa: E226,E501 missing whitespace around operator class TryExceptImportTest(TemplateTest): def test_FailCase(self): """ Test situation where an inline #import statement will get relocated """ source = ''' #def myFunction() Ahoy! #try #import sys #except ImportError $print "This will never happen!" #end try #end def ''' # This should raise an IndentationError (if the bug exists) klass = Template.compile( source=source, compilerSettings={'useLegacyImportMode': False}) t = klass(namespaces={'foo': 1234}) # noqa: F841 class ClassMethodSupport(TemplateTest): def test_BasicDecorator(self): template = ''' #@classmethod #def myClassMethod() #return '$foo = %s' % $foo #end def ''' template = Template.compile(source=template) try: rc = template.myClassMethod(foo='bar') assert rc == '$foo = bar', \ (rc, 'Template class method didn\'t return what I expected') except AttributeError as ex: self.fail(ex) class StaticMethodSupport(TemplateTest): def test_BasicDecorator(self): template = ''' #@staticmethod #def myStaticMethod() #return '$foo = %s' % $foo #end def ''' template = Template.compile(source=template) try: rc = template.myStaticMethod(foo='bar') assert rc == '$foo = bar', \ (rc, 'Template class method didn\'t return what I expected') except AttributeError as ex: self.fail(ex) class MultipleInheritanceSupport(TemplateTest): def runTest(self): template = ''' #extends Cheetah.Tests.Boinker, Cheetah.Tests.Pinger #def foo() #return [4,5] + $boink() #end def ''' template = Template.compile(template) template = template() result = template.foo() assert result == [4, 5, 1, 2, 3], (result, 'Unexpected result') class SubclassSearchListTest(TemplateTest): ''' Verify that if we subclass Template, we can still use attributes on that subclass in the searchList ''' def runTest(self): class Sub(Template): greeting = 'Hola' tmpl = Sub('''When we meet, I say "${greeting}"''') self.assertEqual(unicode(tmpl), 'When we meet, I say "Hola"')