pypage 2.0.8__tar.gz → 2.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pypage-2.0.8 → pypage-2.1.0}/PKG-INFO +53 -30
- {pypage-2.0.8 → pypage-2.1.0}/README.rst +47 -21
- {pypage-2.0.8 → pypage-2.1.0}/pypage.egg-info/PKG-INFO +53 -30
- {pypage-2.0.8 → pypage-2.1.0}/pypage.py +11 -6
- {pypage-2.0.8 → pypage-2.1.0}/setup.py +13 -7
- {pypage-2.0.8 → pypage-2.1.0}/LICENSE.txt +0 -0
- {pypage-2.0.8 → pypage-2.1.0}/pypage.egg-info/SOURCES.txt +0 -0
- {pypage-2.0.8 → pypage-2.1.0}/pypage.egg-info/dependency_links.txt +0 -0
- {pypage-2.0.8 → pypage-2.1.0}/pypage.egg-info/entry_points.txt +0 -0
- {pypage-2.0.8 → pypage-2.1.0}/pypage.egg-info/top_level.txt +0 -0
- {pypage-2.0.8 → pypage-2.1.0}/setup.cfg +0 -0
@@ -1,15 +1,17 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pypage
|
3
|
-
Version: 2.0
|
3
|
+
Version: 2.1.0
|
4
4
|
Summary: Light-weight Python Templating Engine
|
5
5
|
Home-page: https://github.com/arjun-menon/pypage
|
6
|
-
Download-URL: https://github.com/arjun-menon/pypage/archive/v2.0.
|
6
|
+
Download-URL: https://github.com/arjun-menon/pypage/archive/v2.1.0.tar.gz
|
7
7
|
Author: Arjun G. Menon
|
8
8
|
Author-email: contact@arjungmenon.com
|
9
|
-
License: Apache
|
10
|
-
Keywords: templating
|
9
|
+
License: Apache-2.0
|
10
|
+
Keywords: templating engine text processing static generator,templating engine,text processing,template,templates
|
11
11
|
Classifier: Topic :: Text Processing
|
12
|
+
Classifier: Intended Audience :: Developers
|
12
13
|
Classifier: Topic :: Internet :: WWW/HTTP
|
14
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
13
15
|
Classifier: Topic :: Text Processing :: Markup :: HTML
|
14
16
|
Classifier: License :: OSI Approved :: Apache Software License
|
15
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
@@ -20,26 +22,22 @@ Classifier: Operating System :: OS Independent
|
|
20
22
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
21
23
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
22
24
|
Classifier: Programming Language :: Python :: 2
|
23
|
-
Classifier: Programming Language :: Python :: 2.7
|
24
25
|
Classifier: Programming Language :: Python :: 3
|
25
|
-
Classifier: Programming Language :: Python :: 3.2
|
26
|
-
Classifier: Programming Language :: Python :: 3.3
|
27
|
-
Classifier: Programming Language :: Python :: 3.4
|
28
|
-
Classifier: Programming Language :: Python :: 3.5
|
29
26
|
License-File: LICENSE.txt
|
30
27
|
|
31
|
-
|
32
|
-
|
28
|
+
PyPage |pypi| |docs| |test|
|
29
|
+
===========================
|
33
30
|
|
34
|
-
|
31
|
+
PyPage is a document template engine for Python programmers with a
|
35
32
|
short learning curve.
|
36
33
|
|
37
|
-
**Why use
|
34
|
+
**Why use PyPage?**
|
38
35
|
|
39
36
|
- Easy to pick up. Syntax similar to Python's.
|
40
37
|
- You need an eval-based template engine.
|
41
38
|
|
42
|
-
|
39
|
+
PyPage supports Python 3.x and 2.7, and has been tested
|
40
|
+
(using `test_cmd <https://github.com/arjun-menon/test_cmd>`_) on CPython and PyPy.
|
43
41
|
|
44
42
|
**What does it look like?**
|
45
43
|
|
@@ -56,7 +54,7 @@ pypage supports Python 3.x and 2.7, and has been on CPython and PyPy.
|
|
56
54
|
|
57
55
|
**Installation**
|
58
56
|
|
59
|
-
You can `install <https://docs.python.org/3/installing/>`_
|
57
|
+
You can `install <https://docs.python.org/3/installing/>`_ PyPage easily with `pip <https://pip.pypa.io/en/stable/>`_:
|
60
58
|
|
61
59
|
.. code::
|
62
60
|
|
@@ -64,6 +62,29 @@ You can `install <https://docs.python.org/3/installing/>`_ pypage easily with `p
|
|
64
62
|
|
65
63
|
Try running ``pypage -h`` to see the command-line options available.
|
66
64
|
|
65
|
+
|
66
|
+
**Why another templating language?**
|
67
|
+
|
68
|
+
PyPage is lets you embed Python code easily and flexibly in textual documents (such as Markdown_, HTML, reStructuredText_, plain text, etc). It lets you construct powerful programmatically-generated documents by embedding Python code in an elegant and flexible manner. Its syntax is similar to and partially inspired by the templating languages Jinja_ and Liquid_.
|
69
|
+
|
70
|
+
While there are many templating engines out there, the primarily advantage of PyPage is the fact that its syntax is very close to Python's, and therefore the learning curve is very short for Python programmers.
|
71
|
+
|
72
|
+
Rather than create a new mini domain-specific language for constructs such as ``for`` and ``if``, PyPage does a teeny tiny bit of obvious string manipulation, and passes your logical directives unaltered to the Python interpreter. As such, PyPage inherits Python's syntax for the most part. For example, ``for`` loops in PyPage get converted into Python's generator expressions. The ``for`` loop in a Python generator expression (or list comprehension) is far more powerful than its regular ``for`` loop. This means that PyPage ``for`` loops are richer and more expressive than you'd otherwise expect, while the learning curve is nearly non-existent.
|
73
|
+
|
74
|
+
The primary disadvantage of using PyPage instead of a templating engine like Liquid is that PyPage does not operate on a restricted non-Turing-complete subset of programming languages, as Liquid for instance does. Liquid allows untrusted users to write and upload their own templates, because the expressiveness of Liquid is limited such that there is an implicit guarantee that the template will be processed in a reasonable (probably linear) amount of time using a reasonable amount of system resources. As such, Liquid's templating language is rather limited -- it offers a limited number of pre-defined functions/filters, and the overall flexibility of the language has been constrained in order to guarantee termination in a reasonable amount of time.
|
75
|
+
|
76
|
+
PyPage, on the other hand gives the template writer full unfettered access to the Python interpreter. As such, PyPage is meant only for use in trusted contexts (or containers), and in some ways it's similar to PHP in that a you're mixing a full-blown programming language (Python) and text that could be HTML.
|
77
|
+
|
78
|
+
This brings us to another topic: mixing code and UI. It is generally frowned upon to mix logic/code and the UI (or "view"). So it is good practise to not do any intelligent processing within your PyPage template. Instead, you can do it in a separate program, and pass an *environment* containing the results, to PyPage. An environment is a dictionary of variables that is passed to Python's ``exec``, and is therefore accessible from all of the code in the PyPage template. From within your template you can focus solely on how to transform these input variables into the HTML/rST/other page you're building.
|
79
|
+
|
80
|
+
A pleasant aspect of PyPage, in comparison to other templating languages is that you don't have to learn much new syntax. It's probably the easiest to learn and most *flexible* templating language out there. It is highly flexible because of the plethora of easy-to-use powerful constructs that PyPage offers.
|
81
|
+
|
82
|
+
.. _Markdown: https://en.wikipedia.org/wiki/Markdown
|
83
|
+
.. _reStructuredText: http://docutils.sourceforge.net/docs/user/rst/quickref.html
|
84
|
+
.. _Liquid: https://github.com/Shopify/liquid/wiki/Liquid-for-Designers
|
85
|
+
.. _Jinja: https://github.com/pallets/jinja
|
86
|
+
|
87
|
+
|
67
88
|
.. contents:: **Table of Contents**
|
68
89
|
|
69
90
|
|
@@ -85,7 +106,7 @@ example of an inline code tag:
|
|
85
106
|
|
86
107
|
There are {{ 5 + 2 }} days in a week.
|
87
108
|
|
88
|
-
The above, when processed by
|
109
|
+
The above, when processed by PyPage, yields:
|
89
110
|
|
90
111
|
::
|
91
112
|
|
@@ -127,7 +148,7 @@ for all code tags in the same file.
|
|
127
148
|
|
128
149
|
As such, a variable instantiated in a code tag at the
|
129
150
|
beginning of the document, will be available to all other code tags in
|
130
|
-
the document. When
|
151
|
+
the document. When PyPage is invoked as library, an initial seed
|
131
152
|
environment consisting of a Python dictionary mapping variable names to
|
132
153
|
values, can be provided.
|
133
154
|
|
@@ -198,7 +219,7 @@ It's best to explain this with an example:
|
|
198
219
|
{% %}
|
199
220
|
|
200
221
|
When the above template is run, the resulting page will contain a
|
201
|
-
randomly chosen greeting. As is evident,
|
222
|
+
randomly chosen greeting. As is evident, PyPage syntax for if/elif/else
|
202
223
|
conditions closely mirrors Python's. The terminal ``{% %}`` can be
|
203
224
|
replaced with an ``{% endif %}`` with no change in meaning (as with any
|
204
225
|
block tag).
|
@@ -214,7 +235,7 @@ Let's start with a simple example:
|
|
214
235
|
|
215
236
|
This will print out the vowels with a space after every character.
|
216
237
|
|
217
|
-
Now that's an ordinary for loop.
|
238
|
+
Now that's an ordinary for loop. PyPage permits for loops that are more
|
218
239
|
expressive than traditional Python for loops, by leveraging Python's
|
219
240
|
*generator expressions*.
|
220
241
|
|
@@ -241,7 +262,7 @@ The above loop would result in:
|
|
241
262
|
3 ~ b
|
242
263
|
3 ~ c
|
243
264
|
|
244
|
-
*Internally*,
|
265
|
+
*Internally*, PyPage morphs the expression
|
245
266
|
``for x in [1,2,3] for y in ['a','b','c']`` into the generator
|
246
267
|
expression ``(x, y) for x in [1,2,3] for y in ['a','b','c']``. It
|
247
268
|
exposes the the loop variables ``x`` and ``y`` by injecting them into
|
@@ -249,7 +270,7 @@ your namespace.
|
|
249
270
|
|
250
271
|
*Note:* Injected loop variables replace variables with the same name for
|
251
272
|
the duration of the loop. After the loop, the old variables with the
|
252
|
-
identical names are restored (
|
273
|
+
identical names are restored (PyPage backs them up).
|
253
274
|
|
254
275
|
While Loops
|
255
276
|
^^^^^^^^^^^
|
@@ -289,13 +310,13 @@ evaluated.
|
|
289
310
|
Long Loops
|
290
311
|
''''''''''
|
291
312
|
|
292
|
-
If a loop runs *for more than 2 seconds*,
|
313
|
+
If a loop runs *for more than 2 seconds*, PyPage stops executing it, and
|
293
314
|
writes an error message to ``stdout`` saying that the loop had been
|
294
|
-
terminated. As
|
315
|
+
terminated. As PyPage is mostly intended to be used as a templating
|
295
316
|
language, loops generally shouldn't be running for longer than two
|
296
317
|
seconds, and this timeout was added to make it easier to catch accidental
|
297
318
|
infinite loops. If you actually need a loop to run for longer than 2
|
298
|
-
|
319
|
+
seconds, you can add the keyword ``slow`` right after the condition expression
|
299
320
|
(``{{% while condition slow %}}``), and that would suppress this 2-second timeout.
|
300
321
|
|
301
322
|
Capture Blocks
|
@@ -320,10 +341,10 @@ Finer Details
|
|
320
341
|
Inheritance (with inject and exists)
|
321
342
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
322
343
|
|
323
|
-
The approach taken by
|
344
|
+
The approach taken by PyPage toward template inheritance is quite distinct from that of other
|
324
345
|
templating engines (`like Jinja's <http://jinja.pocoo.org/docs/2.10/templates/#template-inheritance>`_).
|
325
|
-
It's a lot simpler. You call a
|
326
|
-
to inject (i.e. "*extend*" in Jinja parlance), and
|
346
|
+
It's a lot simpler. You call a PyPage-provided function ``inject`` with the path of a *PyPage template* you want
|
347
|
+
to inject (i.e. "*extend*" in Jinja parlance), and PyPage will process that template under the current scope (with all
|
327
348
|
previously defined variables being available to the injected template), and the ``inject`` function will return its output.
|
328
349
|
|
329
350
|
A base template could look like this:
|
@@ -367,7 +388,7 @@ and is not present. The output of the "dervied" template is clear and obvious, w
|
|
367
388
|
The include function
|
368
389
|
''''''''''''''''''''
|
369
390
|
|
370
|
-
If you want to include (as in, substitute) a file directly without processing it with
|
391
|
+
If you want to include (as in, substitute) a file directly without processing it with PyPage, you can use the
|
371
392
|
``include`` function. It functions like the ``inject`` function, taking the path to a file as argument, and
|
372
393
|
returning the contents of the file unprocessed.
|
373
394
|
|
@@ -424,7 +445,7 @@ whitespace in the generated document.
|
|
424
445
|
Automatic Indentation
|
425
446
|
'''''''''''''''''''''
|
426
447
|
|
427
|
-
|
448
|
+
PyPage smartly handles indentation for you. In a multi-line code tag, if
|
428
449
|
you consistently indent your Python code with a specific amount of
|
429
450
|
whitespace, that indentation will be stripped off before executing the
|
430
451
|
code block (as Python is indentation-sensitive), and the resulting
|
@@ -467,7 +488,7 @@ would produce the following output:
|
|
467
488
|
Note that the ``Hello!`` was indented with same whitespace that the code
|
468
489
|
in the code block was.
|
469
490
|
|
470
|
-
|
491
|
+
PyPage automatically intends the output of a multi-line tag to match the
|
471
492
|
indentation level of the code tag. The number of whitespace characters
|
472
493
|
at the beginning of the second line of the code block determines the
|
473
494
|
indentation level for the whole block. All lines of code following the
|
@@ -484,3 +505,5 @@ License
|
|
484
505
|
:target: https://pypi.python.org/pypi/pypage
|
485
506
|
.. |docs| image:: https://readthedocs.org/projects/pypage/badge/?version=latest&style=flat
|
486
507
|
:target: https://pypage.readthedocs.io/en/latest/
|
508
|
+
.. |test| image:: https://github.com/arjun-menon/pypage/actions/workflows/test.yml/badge.svg
|
509
|
+
:target: https://github.com/arjun-menon/pypage/actions/workflows/test.yml/
|
@@ -1,15 +1,16 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
PyPage |pypi| |docs| |test|
|
2
|
+
===========================
|
3
3
|
|
4
|
-
|
4
|
+
PyPage is a document template engine for Python programmers with a
|
5
5
|
short learning curve.
|
6
6
|
|
7
|
-
**Why use
|
7
|
+
**Why use PyPage?**
|
8
8
|
|
9
9
|
- Easy to pick up. Syntax similar to Python's.
|
10
10
|
- You need an eval-based template engine.
|
11
11
|
|
12
|
-
|
12
|
+
PyPage supports Python 3.x and 2.7, and has been tested
|
13
|
+
(using `test_cmd <https://github.com/arjun-menon/test_cmd>`_) on CPython and PyPy.
|
13
14
|
|
14
15
|
**What does it look like?**
|
15
16
|
|
@@ -26,7 +27,7 @@ pypage supports Python 3.x and 2.7, and has been on CPython and PyPy.
|
|
26
27
|
|
27
28
|
**Installation**
|
28
29
|
|
29
|
-
You can `install <https://docs.python.org/3/installing/>`_
|
30
|
+
You can `install <https://docs.python.org/3/installing/>`_ PyPage easily with `pip <https://pip.pypa.io/en/stable/>`_:
|
30
31
|
|
31
32
|
.. code::
|
32
33
|
|
@@ -34,6 +35,29 @@ You can `install <https://docs.python.org/3/installing/>`_ pypage easily with `p
|
|
34
35
|
|
35
36
|
Try running ``pypage -h`` to see the command-line options available.
|
36
37
|
|
38
|
+
|
39
|
+
**Why another templating language?**
|
40
|
+
|
41
|
+
PyPage is lets you embed Python code easily and flexibly in textual documents (such as Markdown_, HTML, reStructuredText_, plain text, etc). It lets you construct powerful programmatically-generated documents by embedding Python code in an elegant and flexible manner. Its syntax is similar to and partially inspired by the templating languages Jinja_ and Liquid_.
|
42
|
+
|
43
|
+
While there are many templating engines out there, the primarily advantage of PyPage is the fact that its syntax is very close to Python's, and therefore the learning curve is very short for Python programmers.
|
44
|
+
|
45
|
+
Rather than create a new mini domain-specific language for constructs such as ``for`` and ``if``, PyPage does a teeny tiny bit of obvious string manipulation, and passes your logical directives unaltered to the Python interpreter. As such, PyPage inherits Python's syntax for the most part. For example, ``for`` loops in PyPage get converted into Python's generator expressions. The ``for`` loop in a Python generator expression (or list comprehension) is far more powerful than its regular ``for`` loop. This means that PyPage ``for`` loops are richer and more expressive than you'd otherwise expect, while the learning curve is nearly non-existent.
|
46
|
+
|
47
|
+
The primary disadvantage of using PyPage instead of a templating engine like Liquid is that PyPage does not operate on a restricted non-Turing-complete subset of programming languages, as Liquid for instance does. Liquid allows untrusted users to write and upload their own templates, because the expressiveness of Liquid is limited such that there is an implicit guarantee that the template will be processed in a reasonable (probably linear) amount of time using a reasonable amount of system resources. As such, Liquid's templating language is rather limited -- it offers a limited number of pre-defined functions/filters, and the overall flexibility of the language has been constrained in order to guarantee termination in a reasonable amount of time.
|
48
|
+
|
49
|
+
PyPage, on the other hand gives the template writer full unfettered access to the Python interpreter. As such, PyPage is meant only for use in trusted contexts (or containers), and in some ways it's similar to PHP in that a you're mixing a full-blown programming language (Python) and text that could be HTML.
|
50
|
+
|
51
|
+
This brings us to another topic: mixing code and UI. It is generally frowned upon to mix logic/code and the UI (or "view"). So it is good practise to not do any intelligent processing within your PyPage template. Instead, you can do it in a separate program, and pass an *environment* containing the results, to PyPage. An environment is a dictionary of variables that is passed to Python's ``exec``, and is therefore accessible from all of the code in the PyPage template. From within your template you can focus solely on how to transform these input variables into the HTML/rST/other page you're building.
|
52
|
+
|
53
|
+
A pleasant aspect of PyPage, in comparison to other templating languages is that you don't have to learn much new syntax. It's probably the easiest to learn and most *flexible* templating language out there. It is highly flexible because of the plethora of easy-to-use powerful constructs that PyPage offers.
|
54
|
+
|
55
|
+
.. _Markdown: https://en.wikipedia.org/wiki/Markdown
|
56
|
+
.. _reStructuredText: http://docutils.sourceforge.net/docs/user/rst/quickref.html
|
57
|
+
.. _Liquid: https://github.com/Shopify/liquid/wiki/Liquid-for-Designers
|
58
|
+
.. _Jinja: https://github.com/pallets/jinja
|
59
|
+
|
60
|
+
|
37
61
|
.. contents:: **Table of Contents**
|
38
62
|
|
39
63
|
|
@@ -55,7 +79,7 @@ example of an inline code tag:
|
|
55
79
|
|
56
80
|
There are {{ 5 + 2 }} days in a week.
|
57
81
|
|
58
|
-
The above, when processed by
|
82
|
+
The above, when processed by PyPage, yields:
|
59
83
|
|
60
84
|
::
|
61
85
|
|
@@ -97,7 +121,7 @@ for all code tags in the same file.
|
|
97
121
|
|
98
122
|
As such, a variable instantiated in a code tag at the
|
99
123
|
beginning of the document, will be available to all other code tags in
|
100
|
-
the document. When
|
124
|
+
the document. When PyPage is invoked as library, an initial seed
|
101
125
|
environment consisting of a Python dictionary mapping variable names to
|
102
126
|
values, can be provided.
|
103
127
|
|
@@ -168,7 +192,7 @@ It's best to explain this with an example:
|
|
168
192
|
{% %}
|
169
193
|
|
170
194
|
When the above template is run, the resulting page will contain a
|
171
|
-
randomly chosen greeting. As is evident,
|
195
|
+
randomly chosen greeting. As is evident, PyPage syntax for if/elif/else
|
172
196
|
conditions closely mirrors Python's. The terminal ``{% %}`` can be
|
173
197
|
replaced with an ``{% endif %}`` with no change in meaning (as with any
|
174
198
|
block tag).
|
@@ -184,7 +208,7 @@ Let's start with a simple example:
|
|
184
208
|
|
185
209
|
This will print out the vowels with a space after every character.
|
186
210
|
|
187
|
-
Now that's an ordinary for loop.
|
211
|
+
Now that's an ordinary for loop. PyPage permits for loops that are more
|
188
212
|
expressive than traditional Python for loops, by leveraging Python's
|
189
213
|
*generator expressions*.
|
190
214
|
|
@@ -211,7 +235,7 @@ The above loop would result in:
|
|
211
235
|
3 ~ b
|
212
236
|
3 ~ c
|
213
237
|
|
214
|
-
*Internally*,
|
238
|
+
*Internally*, PyPage morphs the expression
|
215
239
|
``for x in [1,2,3] for y in ['a','b','c']`` into the generator
|
216
240
|
expression ``(x, y) for x in [1,2,3] for y in ['a','b','c']``. It
|
217
241
|
exposes the the loop variables ``x`` and ``y`` by injecting them into
|
@@ -219,7 +243,7 @@ your namespace.
|
|
219
243
|
|
220
244
|
*Note:* Injected loop variables replace variables with the same name for
|
221
245
|
the duration of the loop. After the loop, the old variables with the
|
222
|
-
identical names are restored (
|
246
|
+
identical names are restored (PyPage backs them up).
|
223
247
|
|
224
248
|
While Loops
|
225
249
|
^^^^^^^^^^^
|
@@ -259,13 +283,13 @@ evaluated.
|
|
259
283
|
Long Loops
|
260
284
|
''''''''''
|
261
285
|
|
262
|
-
If a loop runs *for more than 2 seconds*,
|
286
|
+
If a loop runs *for more than 2 seconds*, PyPage stops executing it, and
|
263
287
|
writes an error message to ``stdout`` saying that the loop had been
|
264
|
-
terminated. As
|
288
|
+
terminated. As PyPage is mostly intended to be used as a templating
|
265
289
|
language, loops generally shouldn't be running for longer than two
|
266
290
|
seconds, and this timeout was added to make it easier to catch accidental
|
267
291
|
infinite loops. If you actually need a loop to run for longer than 2
|
268
|
-
|
292
|
+
seconds, you can add the keyword ``slow`` right after the condition expression
|
269
293
|
(``{{% while condition slow %}}``), and that would suppress this 2-second timeout.
|
270
294
|
|
271
295
|
Capture Blocks
|
@@ -290,10 +314,10 @@ Finer Details
|
|
290
314
|
Inheritance (with inject and exists)
|
291
315
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
292
316
|
|
293
|
-
The approach taken by
|
317
|
+
The approach taken by PyPage toward template inheritance is quite distinct from that of other
|
294
318
|
templating engines (`like Jinja's <http://jinja.pocoo.org/docs/2.10/templates/#template-inheritance>`_).
|
295
|
-
It's a lot simpler. You call a
|
296
|
-
to inject (i.e. "*extend*" in Jinja parlance), and
|
319
|
+
It's a lot simpler. You call a PyPage-provided function ``inject`` with the path of a *PyPage template* you want
|
320
|
+
to inject (i.e. "*extend*" in Jinja parlance), and PyPage will process that template under the current scope (with all
|
297
321
|
previously defined variables being available to the injected template), and the ``inject`` function will return its output.
|
298
322
|
|
299
323
|
A base template could look like this:
|
@@ -337,7 +361,7 @@ and is not present. The output of the "dervied" template is clear and obvious, w
|
|
337
361
|
The include function
|
338
362
|
''''''''''''''''''''
|
339
363
|
|
340
|
-
If you want to include (as in, substitute) a file directly without processing it with
|
364
|
+
If you want to include (as in, substitute) a file directly without processing it with PyPage, you can use the
|
341
365
|
``include`` function. It functions like the ``inject`` function, taking the path to a file as argument, and
|
342
366
|
returning the contents of the file unprocessed.
|
343
367
|
|
@@ -394,7 +418,7 @@ whitespace in the generated document.
|
|
394
418
|
Automatic Indentation
|
395
419
|
'''''''''''''''''''''
|
396
420
|
|
397
|
-
|
421
|
+
PyPage smartly handles indentation for you. In a multi-line code tag, if
|
398
422
|
you consistently indent your Python code with a specific amount of
|
399
423
|
whitespace, that indentation will be stripped off before executing the
|
400
424
|
code block (as Python is indentation-sensitive), and the resulting
|
@@ -437,7 +461,7 @@ would produce the following output:
|
|
437
461
|
Note that the ``Hello!`` was indented with same whitespace that the code
|
438
462
|
in the code block was.
|
439
463
|
|
440
|
-
|
464
|
+
PyPage automatically intends the output of a multi-line tag to match the
|
441
465
|
indentation level of the code tag. The number of whitespace characters
|
442
466
|
at the beginning of the second line of the code block determines the
|
443
467
|
indentation level for the whole block. All lines of code following the
|
@@ -454,3 +478,5 @@ License
|
|
454
478
|
:target: https://pypi.python.org/pypi/pypage
|
455
479
|
.. |docs| image:: https://readthedocs.org/projects/pypage/badge/?version=latest&style=flat
|
456
480
|
:target: https://pypage.readthedocs.io/en/latest/
|
481
|
+
.. |test| image:: https://github.com/arjun-menon/pypage/actions/workflows/test.yml/badge.svg
|
482
|
+
:target: https://github.com/arjun-menon/pypage/actions/workflows/test.yml/
|
@@ -1,15 +1,17 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: pypage
|
3
|
-
Version: 2.0
|
3
|
+
Version: 2.1.0
|
4
4
|
Summary: Light-weight Python Templating Engine
|
5
5
|
Home-page: https://github.com/arjun-menon/pypage
|
6
|
-
Download-URL: https://github.com/arjun-menon/pypage/archive/v2.0.
|
6
|
+
Download-URL: https://github.com/arjun-menon/pypage/archive/v2.1.0.tar.gz
|
7
7
|
Author: Arjun G. Menon
|
8
8
|
Author-email: contact@arjungmenon.com
|
9
|
-
License: Apache
|
10
|
-
Keywords: templating
|
9
|
+
License: Apache-2.0
|
10
|
+
Keywords: templating engine text processing static generator,templating engine,text processing,template,templates
|
11
11
|
Classifier: Topic :: Text Processing
|
12
|
+
Classifier: Intended Audience :: Developers
|
12
13
|
Classifier: Topic :: Internet :: WWW/HTTP
|
14
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
13
15
|
Classifier: Topic :: Text Processing :: Markup :: HTML
|
14
16
|
Classifier: License :: OSI Approved :: Apache Software License
|
15
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
@@ -20,26 +22,22 @@ Classifier: Operating System :: OS Independent
|
|
20
22
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
21
23
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
22
24
|
Classifier: Programming Language :: Python :: 2
|
23
|
-
Classifier: Programming Language :: Python :: 2.7
|
24
25
|
Classifier: Programming Language :: Python :: 3
|
25
|
-
Classifier: Programming Language :: Python :: 3.2
|
26
|
-
Classifier: Programming Language :: Python :: 3.3
|
27
|
-
Classifier: Programming Language :: Python :: 3.4
|
28
|
-
Classifier: Programming Language :: Python :: 3.5
|
29
26
|
License-File: LICENSE.txt
|
30
27
|
|
31
|
-
|
32
|
-
|
28
|
+
PyPage |pypi| |docs| |test|
|
29
|
+
===========================
|
33
30
|
|
34
|
-
|
31
|
+
PyPage is a document template engine for Python programmers with a
|
35
32
|
short learning curve.
|
36
33
|
|
37
|
-
**Why use
|
34
|
+
**Why use PyPage?**
|
38
35
|
|
39
36
|
- Easy to pick up. Syntax similar to Python's.
|
40
37
|
- You need an eval-based template engine.
|
41
38
|
|
42
|
-
|
39
|
+
PyPage supports Python 3.x and 2.7, and has been tested
|
40
|
+
(using `test_cmd <https://github.com/arjun-menon/test_cmd>`_) on CPython and PyPy.
|
43
41
|
|
44
42
|
**What does it look like?**
|
45
43
|
|
@@ -56,7 +54,7 @@ pypage supports Python 3.x and 2.7, and has been on CPython and PyPy.
|
|
56
54
|
|
57
55
|
**Installation**
|
58
56
|
|
59
|
-
You can `install <https://docs.python.org/3/installing/>`_
|
57
|
+
You can `install <https://docs.python.org/3/installing/>`_ PyPage easily with `pip <https://pip.pypa.io/en/stable/>`_:
|
60
58
|
|
61
59
|
.. code::
|
62
60
|
|
@@ -64,6 +62,29 @@ You can `install <https://docs.python.org/3/installing/>`_ pypage easily with `p
|
|
64
62
|
|
65
63
|
Try running ``pypage -h`` to see the command-line options available.
|
66
64
|
|
65
|
+
|
66
|
+
**Why another templating language?**
|
67
|
+
|
68
|
+
PyPage is lets you embed Python code easily and flexibly in textual documents (such as Markdown_, HTML, reStructuredText_, plain text, etc). It lets you construct powerful programmatically-generated documents by embedding Python code in an elegant and flexible manner. Its syntax is similar to and partially inspired by the templating languages Jinja_ and Liquid_.
|
69
|
+
|
70
|
+
While there are many templating engines out there, the primarily advantage of PyPage is the fact that its syntax is very close to Python's, and therefore the learning curve is very short for Python programmers.
|
71
|
+
|
72
|
+
Rather than create a new mini domain-specific language for constructs such as ``for`` and ``if``, PyPage does a teeny tiny bit of obvious string manipulation, and passes your logical directives unaltered to the Python interpreter. As such, PyPage inherits Python's syntax for the most part. For example, ``for`` loops in PyPage get converted into Python's generator expressions. The ``for`` loop in a Python generator expression (or list comprehension) is far more powerful than its regular ``for`` loop. This means that PyPage ``for`` loops are richer and more expressive than you'd otherwise expect, while the learning curve is nearly non-existent.
|
73
|
+
|
74
|
+
The primary disadvantage of using PyPage instead of a templating engine like Liquid is that PyPage does not operate on a restricted non-Turing-complete subset of programming languages, as Liquid for instance does. Liquid allows untrusted users to write and upload their own templates, because the expressiveness of Liquid is limited such that there is an implicit guarantee that the template will be processed in a reasonable (probably linear) amount of time using a reasonable amount of system resources. As such, Liquid's templating language is rather limited -- it offers a limited number of pre-defined functions/filters, and the overall flexibility of the language has been constrained in order to guarantee termination in a reasonable amount of time.
|
75
|
+
|
76
|
+
PyPage, on the other hand gives the template writer full unfettered access to the Python interpreter. As such, PyPage is meant only for use in trusted contexts (or containers), and in some ways it's similar to PHP in that a you're mixing a full-blown programming language (Python) and text that could be HTML.
|
77
|
+
|
78
|
+
This brings us to another topic: mixing code and UI. It is generally frowned upon to mix logic/code and the UI (or "view"). So it is good practise to not do any intelligent processing within your PyPage template. Instead, you can do it in a separate program, and pass an *environment* containing the results, to PyPage. An environment is a dictionary of variables that is passed to Python's ``exec``, and is therefore accessible from all of the code in the PyPage template. From within your template you can focus solely on how to transform these input variables into the HTML/rST/other page you're building.
|
79
|
+
|
80
|
+
A pleasant aspect of PyPage, in comparison to other templating languages is that you don't have to learn much new syntax. It's probably the easiest to learn and most *flexible* templating language out there. It is highly flexible because of the plethora of easy-to-use powerful constructs that PyPage offers.
|
81
|
+
|
82
|
+
.. _Markdown: https://en.wikipedia.org/wiki/Markdown
|
83
|
+
.. _reStructuredText: http://docutils.sourceforge.net/docs/user/rst/quickref.html
|
84
|
+
.. _Liquid: https://github.com/Shopify/liquid/wiki/Liquid-for-Designers
|
85
|
+
.. _Jinja: https://github.com/pallets/jinja
|
86
|
+
|
87
|
+
|
67
88
|
.. contents:: **Table of Contents**
|
68
89
|
|
69
90
|
|
@@ -85,7 +106,7 @@ example of an inline code tag:
|
|
85
106
|
|
86
107
|
There are {{ 5 + 2 }} days in a week.
|
87
108
|
|
88
|
-
The above, when processed by
|
109
|
+
The above, when processed by PyPage, yields:
|
89
110
|
|
90
111
|
::
|
91
112
|
|
@@ -127,7 +148,7 @@ for all code tags in the same file.
|
|
127
148
|
|
128
149
|
As such, a variable instantiated in a code tag at the
|
129
150
|
beginning of the document, will be available to all other code tags in
|
130
|
-
the document. When
|
151
|
+
the document. When PyPage is invoked as library, an initial seed
|
131
152
|
environment consisting of a Python dictionary mapping variable names to
|
132
153
|
values, can be provided.
|
133
154
|
|
@@ -198,7 +219,7 @@ It's best to explain this with an example:
|
|
198
219
|
{% %}
|
199
220
|
|
200
221
|
When the above template is run, the resulting page will contain a
|
201
|
-
randomly chosen greeting. As is evident,
|
222
|
+
randomly chosen greeting. As is evident, PyPage syntax for if/elif/else
|
202
223
|
conditions closely mirrors Python's. The terminal ``{% %}`` can be
|
203
224
|
replaced with an ``{% endif %}`` with no change in meaning (as with any
|
204
225
|
block tag).
|
@@ -214,7 +235,7 @@ Let's start with a simple example:
|
|
214
235
|
|
215
236
|
This will print out the vowels with a space after every character.
|
216
237
|
|
217
|
-
Now that's an ordinary for loop.
|
238
|
+
Now that's an ordinary for loop. PyPage permits for loops that are more
|
218
239
|
expressive than traditional Python for loops, by leveraging Python's
|
219
240
|
*generator expressions*.
|
220
241
|
|
@@ -241,7 +262,7 @@ The above loop would result in:
|
|
241
262
|
3 ~ b
|
242
263
|
3 ~ c
|
243
264
|
|
244
|
-
*Internally*,
|
265
|
+
*Internally*, PyPage morphs the expression
|
245
266
|
``for x in [1,2,3] for y in ['a','b','c']`` into the generator
|
246
267
|
expression ``(x, y) for x in [1,2,3] for y in ['a','b','c']``. It
|
247
268
|
exposes the the loop variables ``x`` and ``y`` by injecting them into
|
@@ -249,7 +270,7 @@ your namespace.
|
|
249
270
|
|
250
271
|
*Note:* Injected loop variables replace variables with the same name for
|
251
272
|
the duration of the loop. After the loop, the old variables with the
|
252
|
-
identical names are restored (
|
273
|
+
identical names are restored (PyPage backs them up).
|
253
274
|
|
254
275
|
While Loops
|
255
276
|
^^^^^^^^^^^
|
@@ -289,13 +310,13 @@ evaluated.
|
|
289
310
|
Long Loops
|
290
311
|
''''''''''
|
291
312
|
|
292
|
-
If a loop runs *for more than 2 seconds*,
|
313
|
+
If a loop runs *for more than 2 seconds*, PyPage stops executing it, and
|
293
314
|
writes an error message to ``stdout`` saying that the loop had been
|
294
|
-
terminated. As
|
315
|
+
terminated. As PyPage is mostly intended to be used as a templating
|
295
316
|
language, loops generally shouldn't be running for longer than two
|
296
317
|
seconds, and this timeout was added to make it easier to catch accidental
|
297
318
|
infinite loops. If you actually need a loop to run for longer than 2
|
298
|
-
|
319
|
+
seconds, you can add the keyword ``slow`` right after the condition expression
|
299
320
|
(``{{% while condition slow %}}``), and that would suppress this 2-second timeout.
|
300
321
|
|
301
322
|
Capture Blocks
|
@@ -320,10 +341,10 @@ Finer Details
|
|
320
341
|
Inheritance (with inject and exists)
|
321
342
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
322
343
|
|
323
|
-
The approach taken by
|
344
|
+
The approach taken by PyPage toward template inheritance is quite distinct from that of other
|
324
345
|
templating engines (`like Jinja's <http://jinja.pocoo.org/docs/2.10/templates/#template-inheritance>`_).
|
325
|
-
It's a lot simpler. You call a
|
326
|
-
to inject (i.e. "*extend*" in Jinja parlance), and
|
346
|
+
It's a lot simpler. You call a PyPage-provided function ``inject`` with the path of a *PyPage template* you want
|
347
|
+
to inject (i.e. "*extend*" in Jinja parlance), and PyPage will process that template under the current scope (with all
|
327
348
|
previously defined variables being available to the injected template), and the ``inject`` function will return its output.
|
328
349
|
|
329
350
|
A base template could look like this:
|
@@ -367,7 +388,7 @@ and is not present. The output of the "dervied" template is clear and obvious, w
|
|
367
388
|
The include function
|
368
389
|
''''''''''''''''''''
|
369
390
|
|
370
|
-
If you want to include (as in, substitute) a file directly without processing it with
|
391
|
+
If you want to include (as in, substitute) a file directly without processing it with PyPage, you can use the
|
371
392
|
``include`` function. It functions like the ``inject`` function, taking the path to a file as argument, and
|
372
393
|
returning the contents of the file unprocessed.
|
373
394
|
|
@@ -424,7 +445,7 @@ whitespace in the generated document.
|
|
424
445
|
Automatic Indentation
|
425
446
|
'''''''''''''''''''''
|
426
447
|
|
427
|
-
|
448
|
+
PyPage smartly handles indentation for you. In a multi-line code tag, if
|
428
449
|
you consistently indent your Python code with a specific amount of
|
429
450
|
whitespace, that indentation will be stripped off before executing the
|
430
451
|
code block (as Python is indentation-sensitive), and the resulting
|
@@ -467,7 +488,7 @@ would produce the following output:
|
|
467
488
|
Note that the ``Hello!`` was indented with same whitespace that the code
|
468
489
|
in the code block was.
|
469
490
|
|
470
|
-
|
491
|
+
PyPage automatically intends the output of a multi-line tag to match the
|
471
492
|
indentation level of the code tag. The number of whitespace characters
|
472
493
|
at the beginning of the second line of the code block determines the
|
473
494
|
indentation level for the whole block. All lines of code following the
|
@@ -484,3 +505,5 @@ License
|
|
484
505
|
:target: https://pypi.python.org/pypi/pypage
|
485
506
|
.. |docs| image:: https://readthedocs.org/projects/pypage/badge/?version=latest&style=flat
|
486
507
|
:target: https://pypage.readthedocs.io/en/latest/
|
508
|
+
.. |test| image:: https://github.com/arjun-menon/pypage/actions/workflows/test.yml/badge.svg
|
509
|
+
:target: https://github.com/arjun-menon/pypage/actions/workflows/test.yml/
|
@@ -18,7 +18,7 @@
|
|
18
18
|
from __future__ import print_function
|
19
19
|
import string, sys, time, os, json
|
20
20
|
|
21
|
-
pypage_version = '2.0
|
21
|
+
pypage_version = '2.1.0'
|
22
22
|
|
23
23
|
class RootNode(object):
|
24
24
|
"""
|
@@ -62,7 +62,7 @@ class TagNode(object):
|
|
62
62
|
open_delim: string containig the opening delimiter
|
63
63
|
close_delim: string containig the closing delimiter
|
64
64
|
"""
|
65
|
-
escape_delims = {'
|
65
|
+
escape_delims = {('\\' + '{'):'{', ('\\' + '}'):'}'}
|
66
66
|
|
67
67
|
def __init__(self, loc):
|
68
68
|
self.src = str()
|
@@ -383,7 +383,13 @@ class EndBlockTag(BlockTag):
|
|
383
383
|
def __repr__(self):
|
384
384
|
return 'EndBlockTag.\n'
|
385
385
|
|
386
|
-
class
|
386
|
+
class PypageError(Exception):
|
387
|
+
def __init__(self, description='undefined'):
|
388
|
+
self.description = description
|
389
|
+
def __str__(self):
|
390
|
+
return "Error: " + self.description
|
391
|
+
|
392
|
+
class PypageSyntaxError(PypageError):
|
387
393
|
def __init__(self, description='undefined'):
|
388
394
|
self.description = description
|
389
395
|
def __str__(self):
|
@@ -832,10 +838,9 @@ def read_file(filepath):
|
|
832
838
|
with open(filepath, 'r') as source_file:
|
833
839
|
return source_file.read()
|
834
840
|
else:
|
835
|
-
|
836
|
-
sys.exit(1)
|
841
|
+
raise PypageError("File %s does not exist. CWD: %s" % (repr(filepath), os.getcwd()))
|
837
842
|
|
838
|
-
__all__ = ['pypage', 'pypage_version']
|
843
|
+
__all__ = ['pypage', 'pypage_version', PypageError, PypageSyntaxError]
|
839
844
|
|
840
845
|
def main():
|
841
846
|
import argparse
|
@@ -3,9 +3,11 @@
|
|
3
3
|
from setuptools import setup
|
4
4
|
|
5
5
|
from pypage import pypage_version as version
|
6
|
+
|
6
7
|
repo_url = 'https://github.com/arjun-menon/pypage'
|
7
8
|
download_url = '%s/archive/v%s.tar.gz' % (repo_url, version)
|
8
9
|
|
10
|
+
|
9
11
|
def get_long_desc():
|
10
12
|
doc_file_name = 'README.rst'
|
11
13
|
exclude_lines_with_words = ['toctree', 'maxdepth']
|
@@ -14,6 +16,7 @@ def get_long_desc():
|
|
14
16
|
lines = f.readlines()
|
15
17
|
return ''.join(line for line in lines if not any(word in line for word in exclude_lines_with_words))
|
16
18
|
|
19
|
+
|
17
20
|
setup(name='pypage',
|
18
21
|
version=version,
|
19
22
|
description=' Light-weight Python Templating Engine',
|
@@ -22,15 +25,23 @@ setup(name='pypage',
|
|
22
25
|
download_url=download_url,
|
23
26
|
author='Arjun G. Menon',
|
24
27
|
author_email='contact@arjungmenon.com',
|
25
|
-
keywords=
|
26
|
-
|
28
|
+
keywords=[
|
29
|
+
'templating engine text processing static generator',
|
30
|
+
'templating engine',
|
31
|
+
'text processing',
|
32
|
+
'template',
|
33
|
+
'templates'
|
34
|
+
],
|
35
|
+
license='Apache-2.0',
|
27
36
|
py_modules=['pypage'],
|
28
37
|
entry_points={
|
29
38
|
'console_scripts': ['pypage=pypage:main'],
|
30
39
|
},
|
31
40
|
classifiers=[
|
32
41
|
'Topic :: Text Processing',
|
42
|
+
'Intended Audience :: Developers',
|
33
43
|
'Topic :: Internet :: WWW/HTTP',
|
44
|
+
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
|
34
45
|
'Topic :: Text Processing :: Markup :: HTML',
|
35
46
|
'License :: OSI Approved :: Apache Software License',
|
36
47
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
@@ -41,10 +52,5 @@ setup(name='pypage',
|
|
41
52
|
'Programming Language :: Python :: Implementation :: CPython',
|
42
53
|
'Programming Language :: Python :: Implementation :: PyPy',
|
43
54
|
'Programming Language :: Python :: 2',
|
44
|
-
'Programming Language :: Python :: 2.7',
|
45
55
|
'Programming Language :: Python :: 3',
|
46
|
-
'Programming Language :: Python :: 3.2',
|
47
|
-
'Programming Language :: Python :: 3.3',
|
48
|
-
'Programming Language :: Python :: 3.4',
|
49
|
-
'Programming Language :: Python :: 3.5',
|
50
56
|
])
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|