1 2Pyolian: Eolian python bindings and a template-based Eolian generator 3===================================================================== 4 5If you need to generate something based on the Eolian database you are in the 6right place! Pyolian is the python bindings for Eolian and provide a clean and 7pythonic API to Eolian; as a bonus it also provide a template-based 8generator to render custom template files, filling them with a full eolian 9context available. 10 11The template engine is really powerfull and provide all the functionalities you 12would expect from a full blow template engine. It is comparable in syntax and 13features to [Jinja2](http://jinja.pocoo.org/) or the Django template system. If 14you are interested on the implementation detail this generator is bases on the 15great [Pyratemp](https://www.simple-is-better.org/template/pyratemp.html). 16 17 18Installation 19============ 20 21There is nothing to install to use the bindings or the generator, everything is 22included in the efl source tree and it is intended to work directly inside the 23tree, usually at efl compilation time (before the install step). 24 25The only requirement is that **the source tree must be already built** (not 26installed) because pyolian search the eolian .so/.dll inside the source tree. 27 28If you built the efl tree in a custom location (fe, you build out-of-tree) you 29can tell pyolian where to find the built eolian .so files using the 30`EOLIAN_SO_DIR` environment variable. 31 32 33Command line usage 34================== 35The simplest way to use the generator is from the command line, using the 36`src/scripts/pyolian/generator.py` command, the `--help` option state: 37 38``` 39usage: generator.py [-h] [--output FILE] [--cls CLASS_NAME] [--ns NAMESPACE] 40 [--struct STRUCT_NAME] [--enum ENUM_NAME] 41 [--alias ALIAS_NAME] 42 template 43 44Pyolian template based generator. 45 46positional arguments: 47 template The template file to use. (REQUIRED) 48 49optional arguments: 50 -h, --help show this help message and exit 51 --output FILE, -o FILE 52 Where to write the rendered output. If not given will 53 print to stdout. 54 --cls CLASS_NAME The full name of the class to render, ex: 55 Efl.Loop.Timer 56 --ns NAMESPACE The namespace to render, ex: Efl.Loop 57 --struct STRUCT_NAME The name of the struct to render, ex: 58 Efl.Loop.Arguments 59 --enum ENUM_NAME The name of the enum to render, ex: 60 Efl.Loop.Handler.Flags 61 --alias ALIAS_NAME The name of the alias to render, ex: Efl.Font.Size 62``` 63 64Basically you just need a template file, then call the generator with at least 65the template file and one of the context options (cls, ns, struct, enum or alias) 66 67Two example templates can be found in the `efl/src/scripts/pyolian` folder, 68from that directory you can run: 69 70``` 71./generator.py test_gen_class.template --cls Efl.Loop.Timer 72``` 73 74This will rendere the template test_gen_class.template with Efl.Loop.Timer as 75**cls** available in the template, you can of course pass any other class you 76want. 77 78As we did not pass the --output-file parameter the rendered text is printed 79on standard out. 80 81 82Python usage 83============ 84 85To use pyolian from python code you need to import **eolian** and/or the 86**Template** class from the pyolian directory. As this python package is not 87installed you need a little hack to import the package, something like this 88should work: 89 90``` 91# Use pyolian from source (not installed) 92pyolian_path = os.path.join(<efl_root_path>, 'src', 'scripts') 93sys.path.insert(0, pyolian_path) 94from pyolian import eolian 95from pyolian.generator import Template 96``` 97 98Now you can use the full eolian library defined in eolian.py (read the file 99to see all available classes and their properties) or just the Template class 100like this: 101 102``` 103t = Template('test_gen_class.template') 104t.render('output.txt', cls='Efl.Loop.Timer', verbose=True) 105``` 106 107 108Template syntax 109=============== 110 111A template is a normal text file, containing some special placeholders and 112control-structures. there are 3 syntax blocks available: 113 114 115Expressions 116----------- 117 118A template needs some kind of "programming-language" to access variables, 119calculate things, format data, check conditions etc. inside the template. So, 120you could invent and implement an own language therefore -- or you could use an 121already existing and well designed language: Python. 122 123The template engine uses embedded Python-expressions. An expression is 124everything which evaluates to a value, e.g. variables, arithmetics, 125comparisons, boolean expressions, function/method calls, list comprehensions 126etc. And such Python expressions can be directly used in the template. 127 128``` 129${expression}$ 130``` 131 132**expression** can be any expression (e.g. a variable-name, an arithmetic 133calculation, a function-/macro-call etc.), and is evaluated when the template 134is rendered. Whitespace after `${` and before `}$` is ignored. 135 136Generic examples: 137 138 * numbers, strings, lists, tuples, dictionaries, ...: 12.34, "hello", [1,2,3], ... 139 * variable-access: var, mylist[i], mydict["key"], myclass.attr 140 * function/method call: myfunc(...), "foobar".upper() 141 * comparison: (i < 0 or j > 1024) 142 * arithmetics: 1+2 143 144For details, please read the Python-documentation about Python expressions. 145 146Examples (for a template rendered with cls='Efl.Loop.Timer'): 147 148 * `${cls.full_name}$` => 'Efl.Loop.Timer' 149 * `${cls.full_name.replace('.', '_').lower()}$` => 'efl_loop_timer' 150 * `${cls.base_class.full_name if cls.base_class else None}$` => 'Efl.Loop.Consumer' or None 151 * `${', '.join([i.full_name for i in cls.hierarchy])}$` => 'Efl.Loop.Consumer, Efl.Object' 152 153note the incredible flexibility of **expression**, they are basically small 154pieces of python code, so you can use quite all the python syntax in them. 155 156Also note that the context of the template (**cls** in this example) is always 157an instance of a class defined in eolian.py (eolian.Class in this example), you 158must read this file to understand all the available classes with their 159properties and methods. 160 161 162Comments 163-------- 164 165Comments can be used in a template, and they do not appear in the result. They 166are especially useful for (a) documenting the template, (b) temporarily 167disabling parts of the template or (c) suppressing whitespace. 168 169 * `#!...!#` - single-line comment with start and end tag 170 * `#!...` - single-line-comment until end-of-line, incl. newline! 171 172The second version also comments out the newline, and so can be used at the end 173of a line to remove that newline in the result. 174 175Comments can contain anything, but comments may not appear inside substitutions 176or block-tags. 177 178 179Blocks 180------ 181 182The control structures, macros etc. have a special syntax, which consists of a 183start tag (which is named according to the block), optional additional tags, 184and an end-tag: 185 186``` 187<!--(...)--> #! start tag 188 .. 189 .. 190<!--(...)--> #! optional additional tags (e.g. for elif) 191 .. 192 .. 193<!--(end)--> #! end tag 194``` 195 196All tags must stand on their own line, and no code (except a `#!...` comment) is 197allowed after the tag. 198 199All tags which belong to the same block **must have the same indent!** The 200contents of the block does not need to be indented, although it might improve 201the readability (e.g. in HTML) to indent the contents as well. 202 203Nesting blocks is possible, but the tags of nested blocks must have a different 204indent than the tags of the enclosing blocks. Note that you should either use 205spaces or tabs for indentation. Since the template distinguishes between spaces 206and tabs, if you mix spaces and tabs, two indentations might look the same 207(e.g. 8 spaces or 1 tab) but still be different, which might lead to unexpected 208errors. 209 210There's also a single-line version of a block, which does not need to stand on 211its own line, but can be inserted anywhere in the template. But note that this 212version does not support nesting : 213 214``` 215...<!--(...)-->...<!--(...)-->...<!--(end)-->... 216``` 217 218if/elif/else 219------------ 220 221``` 222<!--(if EXPR)--> 223... 224<!--(elif EXPR)--> 225... 226<!--(else)--> 227... 228<!--(end)--> 229``` 230 231The `elif` and `else` branches are optional, and there can be any number of 232`elif` branches. 233 234 235for/else 236-------- 237 238``` 239<!--(for VARS in EXPR)--> 240... 241<!--(else)--> 242... 243<!--(end)--> 244``` 245 246VARS can be a single variable name (e.g. myvar) or a comma-separated list of 247variable-names (e.g. i,val). 248 249The `else` branch is optional, and is executed only if the for loop doesn't 250iterate at all. 251 252 253macro 254----- 255 256Macros are user-defined "sub-templates", and so can contain anything a template 257itself can contain. They can have parameters and are normally used to 258encapsulate parts of a template and to create user-defined "functions". Macros 259can be used in expressions, just like a normal variable or function. 260 261``` 262<!--(macro MACRONAME)--> 263... 264<!--(end)--> 265``` 266 267Note that the last newline (before `<!--(end)-->`) is removed from the macro, so 268that defining and using a macro does not add additional empty lines. 269 270Usage in expressions: 271 272 * `MACRONAME` 273 * `MACRONAME(KEYWORD_ARGS)` 274 275KEYWORD_ARGS can be any number of comma-separated name-value-pairs (name=value, 276...), and these names then will be locally defined inside the macro, in 277addition to those already defined for the whole template. 278 279 280raw 281--- 282 283``` 284<!--(raw)--> 285... 286<!--(end)--> 287``` 288 289Everything inside a `raw` block is passed verbatim to the result. 290 291 292include 293------- 294 295``` 296<!--(include)-->FILENAME<!--(end)--> 297``` 298 299Include another template-file. Only a single filename (+whitespace) is allowed 300inside of the block; if you want to include several files, use several 301include-blocks. 302 303Note that inclusion of other templates is only supported when loading the 304template from a file. For simplicity and security, FILENAME may not contain a 305path, and only files which are in the same directory as the template itself can 306be included. 307 308 309 310Template context 311================ 312 313The following Python-built-in values/functions are available by default in the 314template: 315 316 * `True` 317 * `False` 318 * `None` 319 * `abs()` 320 * `chr()` 321 * `divmod()` 322 * `hash()` 323 * `hex()` 324 * `isinstance()` 325 * `len()` 326 * `max()` 327 * `min()` 328 * `oct()` 329 * `ord()` 330 * `pow()` 331 * `range()` 332 * `round()` 333 * `sorted()` 334 * `sum()` 335 * `unichr()` 336 * `zip()` 337 * `bool()` 338 * `bytes()` 339 * `complex()` 340 * `dict()` 341 * `enumerate()` 342 * `float()` 343 * `int()` 344 * `list()` 345 * `long()` 346 * `reversed()` 347 * `set()` 348 * `str()` 349 * `tuple()` 350 * `unicode()` 351 * `dir()` 352 353Additionally, the functions exists(), default(), setvar() and escape() are 354defined as follows: 355 356 * `exists("varname")` Test if a variable (or any other object) with the given name exists 357 * `default("expr", default=None)` Tries to evaluate the expression expr. 358 If the evaluation succeeds and the result is not None, its value is returned; 359 otherwise, if the expression contains undefined variables/attributes, the 360 default-value is returned instead. Note that expr has to be quoted. 361 * `setvar("name", "expr")` Although there is often a more elegant way, 362 sometimes it is useful or necessary to set variables in the template. 363 Can also be used to capture the output of e.g. an evaluated macro. 364 365Moreover all the Eolian classes and enums (as defined in eolian.py) are available 366in the template, fe: 367 368 * `Function` eolian.Function (class) 369 * `Eolian_Class_Type` eolian.Eolian_Class_Type (enum) 370 371And some other general utilities: 372 373 * `template_file` name of the template used to generate the output 374 * `date` python datetime object (generation time) 375 376 377Where to find more info 378======================= 379 380 * read the eolian.py file (it declare the full eolian API) 381 * read the generator.py file (it's super simple) 382 * read the original [pyratemp docs](https://www.simple-is-better.org/template/pyratemp.html) 383 384 385Note 386==== 387 388This markdown file is mirrored in efl src tree (src/scripts/pyolian) and in 389phab wiki (phab.enlightenment.org/w/pyolian). Don't forget to update the other 390if you change one! 391