Package: templater3
IntroductionGiven some strings (or files), this library extracts a common template between
them (methodlearn) – some people call it “reverse templating”. Having
your template created, you can parse other strings/files using it - theparsemethod will return only what changes in this file (the “blanks”). It
does something like the opposite of what template libraries (such asJinja) do. But for now, it only can identify
fixed variables (it can’t createforandifblocks, for example).If you have the template and the “blanks” you can also fill the blanks with
the methodjoin- it’ll return a string with the template filled. There are
some other features:If you don’t want/need toTemplater(the main class) create the template
for you, you can pass a pre-processed template (created manually or created
before usinglearnand saved somewhere).You can split the learning and parsing process, since the learning process
generally is executed one time and takes a lot of time compared to parsing
process. To turn this process handy,Templaterhas the methodsdump,save,loadandopen, so you can learn and save a template
definition for later loading and parsing how many times you want (you can
also load, learn more and save).templateris simple to use, easy to
learn and does the hard work for you (for example: part of the learning
algorithm is implemented in C for performance). Do you have 5 minutes? So learn
with theExamples.Installationtemplater is available at PyPI, so
installing it is as simple as executing:pip install templater3Or you can download the latest version and install it usingsetup.py:git clone https://github.com/Lee-W/templater
cd templater
python setup.py build installTerminologyThere are some definitions/concepts we should explicit here:Template: the whole object (instance ofTemplater).Document: a string or file that have some kind of pattern. You’ll use
documents to make a template object learn and recognize these patterns, so
later you can use the template object to parse a document and get only the
information that is not “static”.Blocks: the fixed parts of a template. Can change (in number and size)
whenlearnis run.Blanks: also called holes or variables, blanks are the parts in a
template that changes between documents with the same template.Template definition: the information stored in a template that defines it
(it is a Python list with a very simple grammar that describes how the
template is composed).Markers: when you want to save a template, something should be put
between blocks to “mark” the blanks (so the template definition can be
reconstructed later).Named marker: a marker plus a header is called a named marker. They are
handy and more legible since you can access the “blanks” by names instead of
indexes.Doubts? Don’t worry, see theExamplesand you’ll get it.ExamplesAll you need to know is below (and in theexamplesdirectory):>>> from templater import Templater
>>> documents_to_learn = ['<b> spam and eggs </b>', '<b> ham and spam </b>',
                          '<b> white and black </b>'] # list of documents
>>> template = Templater()
>>> for document in documents_to_learn:
...    template.learn(document)
...

>>> print('Template created:', template._template # template definition)
Template created: [None, '<b> ', None, ' and ', None, ' </b>', None]

>>> document_to_parse = '<b> yellow and blue </b>'
>>> print('Parsing other document:', template.parse(document_to_parse))
Parsing other document: ['', 'yellow', 'blue', '']

>>> print('Filling the blanks:', template.join(['', 'red', 'orange', '']))
Filling the blanks: <b> red and orange </b>You can pass pre-processed templates as a list (blanks areNone, blocks are
strings):>>> t2 = Templater(template=[None, 'Music: ', None, ', Band: ', None])
>>> print(t2.join(['', 'Welcome to the Jungle', 'Guns and Roses']))
Music: Welcome to the Jungle, Band: Guns and Roses…or you can pass a string with markers, thenTemplaterwill create the
list for you:>>> t3 = Templater(template='language=#,cool=#', marker='#')
>>> print(t3.join(['', 'Python', 'YES', '']))
language=Python,cool=YESSaving and opening templates is easy:>>> template.save('my-first-template.html', marker='|||')
>>> # and some time later...
>>> loaded_template = Templater.open('my-first-template.html', marker='|||')
>>> print(loaded_template.parse('<b> Romeo and Juliet </b>'))
['', 'Romeo', 'Juliet', '']The difference betweensaveanddumpis thatsavestores the
template string, filling the blanks with a marker anddumpsaves the wholeTemplaterobject withcPickle. The pairs are:saveandopen(raw template string filled with marker)loadanddump(whole object)Note:savealways add a\nto the end of file;loaddeletes trailing\r\nor\nin the end of file (if any).Note-2: when passing a pre-processed template (usingTemplaterinitializer orTemplater.open) make sure itstarts and endswith a
marker.If you are getting a lot of blanks you can configure the learning process: just
adjustmin_block_size- it’s the minimum number of characters permitted to
create a new block in template:>>> str_1 = 'my favorite color is blue'
>>> str_2 = 'my favorite color is violet'
>>> t = Templater() # default min_block_size = 1
>>> t.learn(str_1)
>>> t.learn(str_2)
>>> print(t._template)
[None, 'my favorite color is ', None, 'l', None, 'e', None]We don’t want that'l'and'e'there, right? So:>>> t = Templater(min_block_size=2)
>>> t.learn(str_1)
>>> t.learn(str_2)
>>> print(t._template)
[None, 'my favorite color is ', None]You can also add “headers” to your template - the headers will be the name of
your markers, so you’ll have a template with named markers andparsewill
return adictinstead oflist. It’s more legible than using list
indices, let’s see:>>> import re
>>> # Let's create a regexp that cases with '{{var}}' (it'll be our marker)
>>> regexp_marker = re.compile(r'{{([a-zA-Z0-9_-]*)}}')
>>> template = Templater('{{first-var}}<b>{{second-var}}</b>{{third-var}}',
                         marker=regexp_marker)
>>> # The template knows the name of each marker just using the regexp provided
>>> # Passing marker as regexp to specify named markers also work for Templater.open

>>> print(template.parse('This <b> is </b> a test.'))
{'second-var': ' is ', 'third-var': ' a test.', 'first-var': 'This '}

>>> # To save the template with named markers we need to provide a Python string.
>>> # Templater will call .format() of this string for each marker with its name
>>> template.save('template-with-named-markers.html', marker='--{}--')
>>> # Will save '--first-var--<b>--second-var--</b>--third-var--\n'And if you have a template without headers, just add to it withadd_headersmethod:>>> t = Templater('+<tr><td>+</td><td>+</td></tr>+', marker='+')
>>> t.parse('<tr><td>hello</td><td>world</td></tr>')
['', 'hello', 'world', '']

>>> t.add_headers(['before', 'first-column', 'second-column', 'after'])
>>> t.parse('<tr><td>hello</td><td>world</td></tr>')
{'after': '', 'before': '', 'first-column': 'hello', 'second-column': 'world'}Note: named markers have a problem: you can’t runlearnif you use them.NotesI really want to know if you are using this project and what is your impression
about it. If you have new ideas of features, discovered bugs or just want to
say “thank you, I’m using it!”, please contact me atalvarojusten at gmail.If you want to code some stuff,
justfork it on GitHuband create a
pull request. Some technical notes for you:This project usesTest-Driven Development.The tests are run using Python 3.6 on macOS 10.14.4.You can see the changes between versions inCHANGELOG.rst.This project usessemantic versioning(thanks,Tom Preston-Werner).AuthorThis software is developed byÁlvaro Justen aka Turicas.Many thanks toAdrian Holovaty- he createdtemplatemaker, the project whichtemplaterwas inspired in/forked from - and toEscola de Matemática Aplicada (Fundação Getúlio Vargas)which gives me interesting problems to solve. :-)This software is modified byWei Lee.LicenseGPL version 2