Interfacing with Python

Exposing attributes

It is possible to expose attributes of a Python object to UL4 templates. This is done by setting the class attribute ul4_attrs:

from ll import ul4c

class Person:
   ul4_attrs = {"firstname", "lastname"}

   def __init__(self, firstname, lastname, age):
      self.firstname = firstname
      self.lastname = lastname
      self.age = age

p = Person("John", "Doe", 42)

template = ul4c.Template("<?print p.lastname?>, <?print p.firstname?>")
print(template.renders(p=p))

This will output Doe, John.

Attributes not in ul4_attrs will not be visible:

template = ul4c.Template("<?print p.age?>")
print(template.renders(p=p))

This will output nothing, as the age attribute is not visible and thus p.age returns an undefined object.

Exposing methods

It is also possible to expose methods of a Python object to UL4 templates. This is done by including the method name in the ul4_attrs class attribute:

from ll import ul4c

class Person:
   ul4_attrs = {"fullname"}

   def __init__(self, firstname, lastname):
      self.firstname = firstname
      self.lastname = lastname

   def fullname(self):
      return self.firstname + " " + self.lastname

p = Person("John", "Doe")

template = ul4c.Template("<?print p.fullname()?>")
print(template.renders(p=p))

This will output John Doe.

Furthermore it’s possible to specify that the method needs access to the rendering context (which stores the local variables and the UL4 call stack):

class Person:
   ul4_attrs = {"fullname", "varcount"}

   @ul4c.withcontext
   def varcount(self, context):
      return len(context.vars)

Custom attributes

To customize getting and setting object attributes from UL4 templates the methods ul4_getattr() and ul4_setattr() can be implemented:

from ll import ul4c

class Person:
   ul4_attrs = {"firstname", "lastname"}

   def __init__(self, firstname, lastname, age):
      self.firstname = firstname
      self.lastname = lastname
      self.age = age

   def ul4_getattr(self, name):
      return getattr(self, name).upper()

p = Person("John", "Doe", 42)

template = ul4c.Template("<?print p.lastname?>, <?print p.firstname?>")
print(template.renders(p=p))

This will output DOE, JOHN.

If the object has an attribute ul4_attrs ul4_getattr() will only be called for the attributes in ul4_attrs, otherwise ul4_getattr() will be called for all attributes (and should raise an AttributeError for nonexistent attributes)

Attributes can be made writable by implementing the method ul4_setattr():

from ll import ul4c

class Person:
   ul4_attrs = {"firstname", "lastname"}

   def __init__(self, firstname, lastname, age):
      self.firstname = firstname
      self.lastname = lastname
      self.age = age

   def ul4_setattr(self, name, value):
      return setattr(self, name, value.upper())

p = Person("John", "Doe", 42)

template = ul4c.Template("<?code p.lastname = 'Doe'?><?print p.lastname?>, <?print p.firstname?>")
print(template.renders(p=p))

This will output DOE, John.

If the object has an attribute ul4_attrs ul4_setattr() will only be called for the attributes in ul4_attrs, otherwise ul4_setattr() will be called for all attributes (and should raise an AttributeError for nonexistent or readonly attributes)

Without a ul4_setattr() method, attributes will never be made writable.