How do I use a Python function in a py:for directive

35 views
Skip to first unread message

allen...@gmail.com

unread,
Aug 10, 2012, 4:06:00 PM8/10/12
to gen...@googlegroups.com
I am trying to use a Python function defined in my template in a py:for directive, and am encountering errors. The areainfolist function processes a deep dictionary object in DATA and returns a list of dictionary objects found in the dictionary in DATA, and I cannot change the format of the DATA consumed by the template.

##BEGIN FILE
import os

import genshi.template

TEMPLATE = """<?xml version="1.0"?>
<?python
def areainfolist(areas_cfg):
    results = []
    opt_props = ['isphased', 'keepupcount', 'standbycount', 'iseditkeepup', 'playspindowntimer', 'editspindowntimer', 'depopspindowntimer']
    for k, v in areas_cfg:
        area = {
            "name": k,
            "id": v["id"],
        "popfloor": v["popfloor"],
        "popsoftcap": v["popsoftcap"],
        "popfull": v["popfull"]
        }
    for opt_prop in opt_props:    
        if opt_prop in v:
            area[opt_prop] = v[opt_prop]
    results.append(area)
    return results
?>
<areainfolist xmlns:py="http://genshi.edgewall.org/">
   <area py:for="area in areainfolist(config.shard.areas)" py:attrs="area"></area>
</areainfolist>"""

DATA = {
    "shard": {
        "areas": {
            "ald_main": {
                "id": "4611686023868513034",
                "isphased": "0",
                "keepupcount": "1",
                "planned-load": "120",
                "planned-memory": "3000000000",
                "popfloor": "70",
                "popsoftcap": "150",
                "popfull": "175"
            },
            "dro_knight": {
                "id": "4611686087038969857",
                "isphased": "0",
                "keepupcount": "0",
                "planned-load": "5",
                "planned-memory": "2000000000",
                "popfloor": "12",
                "popsoftcap": "30",
                "popfull": "50"
            }
        }
    }
}

template_filename = "template.xml"
with open(template_filename, "w") as outfile:
    outfile.write(TEMPLATE)

template_loader = genshi.template.TemplateLoader([os.getcwd()])
template = template_loader.load("template.xml")
generated = template.generate(config=DATA)
rendered = generated.render()
print rendered
##BEGIN FILE

When I run this, I get the following error:

Traceback (most recent call last):
  File "genshitest.py", line 62, in <module>
    rendered = generated.render()
  File "/usr/lib64/python2.6/site-packages/genshi/core.py", line 179, in render
    return encode(generator, method=method, encoding=encoding, out=out)
  File "/usr/lib64/python2.6/site-packages/genshi/output.py", line 60, in encode
    return _encode(u''.join(list(iterator)))
  File "/usr/lib64/python2.6/site-packages/genshi/output.py", line 210, in __call__
    for kind, data, pos in stream:
  File "/usr/lib64/python2.6/site-packages/genshi/output.py", line 592, in __call__
    for kind, data, pos in stream:
  File "/usr/lib64/python2.6/site-packages/genshi/output.py", line 698, in __call__
    for kind, data, pos in chain(stream, [(None, None, None)]):
  File "/usr/lib64/python2.6/site-packages/genshi/output.py", line 532, in __call__
    for ev in stream:
  File "/usr/lib64/python2.6/site-packages/genshi/core.py", line 283, in _ensure
    for event in stream:
  File "/usr/lib64/python2.6/site-packages/genshi/template/base.py", line 569, in _include
    for event in stream:
  File "/usr/lib64/python2.6/site-packages/genshi/template/markup.py", line 245, in _match
    for event in stream:
  File "/usr/lib64/python2.6/site-packages/genshi/template/base.py", line 543, in _exec
    for event in stream:
  File "/usr/lib64/python2.6/site-packages/genshi/template/base.py", line 496, in _eval
    for kind, data, pos in stream:
  File "/usr/lib64/python2.6/site-packages/genshi/template/base.py", line 558, in _flatten
    for event in self._flatten(substream, ctxt, **vars):
  File "/usr/lib64/python2.6/site-packages/genshi/template/base.py", line 551, in _flatten
    for event in stream:
  File "/usr/lib64/python2.6/site-packages/genshi/template/directives.py", line 370, in __call__
    iterable = _eval_expr(self.expr, ctxt, **vars)
  File "/usr/lib64/python2.6/site-packages/genshi/template/base.py", line 286, in _eval_expr
    retval = expr.evaluate(ctxt)
  File "/usr/lib64/python2.6/site-packages/genshi/template/eval.py", line 180, in evaluate
    return eval(self.code, _globals, {'__data__': data})
  File "/home/agooch/.workspace/genshitest/src/template.xml", line 21, in <Expression u'iter(areainfolist(config.shard.areas))'>
    <area py:for="area in areainfolist(config.shard.areas)" py:attrs="area"></area>
  File "<string>", line 4, in areainfolist
ValueError: too many values to unpack

If I change out my TEMPLATE to consume list DATA directly:

TEMPLATE = """<?xml version="1.0"?>
<areainfolist xmlns:py="http://genshi.edgewall.org/">
   <area py:for="area in config.shard.areas" py:attrs="area"></area>
</areainfolist>"""

## BEGIN replacement
DATA = {
    "shard": {
        "areas": [
            {
                "id": "4611686023868513034",
                "name": "ald_main",
                "isphased": "0",
                "keepupcount": "1",
                "planned-load": "120",
                "planned-memory": "3000000000",
                "popfloor": "70",
                "popsoftcap": "150",
                "popfull": "175"
            },
            {
                "id": "4611686087038969857",
                "name": "dro_knight",
                "isphased": "0",
                "keepupcount": "0",
                "planned-load": "5",
                "planned-memory": "2000000000",
                "popfloor": "12",
                "popsoftcap": "30",
                "popfull": "50"
            }
        ]
    }
}
## END replacement

I get my expected output:

<?xml version="1.0"?>
<areainfolist>
   <area planned-memory="3000000000" popfloor="70" keepupcount="1" isphased="0" popfull="175" name="ald_main" popsoftcap="150" id="4611686023868513034" planned-load="120"/><area planned-memory="2000000000" popfloor="12" keepupcount="0" isphased="0" popfull="50" name="dro_knight" popsoftcap="30" id="4611686087038969857" planned-load="5"/>
</areainfolist>


Is what I'm trying to do possible with Genshi?  I'm stumped as to how this might be done, but I really need to preserve the structure of the original DATA yet process it as a list built at render time by the function defined in my original TEMPLATE.

TIA,

-Allen

Simon Cross

unread,
Aug 10, 2012, 5:48:01 PM8/10/12
to gen...@googlegroups.com
On Fri, Aug 10, 2012 at 10:06 PM, allen...@gmail.com
<allen...@gmail.com> wrote:
> for k, v in areas_cfg:
> area = {

I think you problem might be the first line above. You probably want
"for k, v in areas_cfg.items():" or something?

Schiavo
Simon
Reply all
Reply to author
Forward
0 new messages