From: Tavis R. <ta...@ca...> - 2001-04-09 06:21:12
|
before someone else catches me on this one: - the sample code I just posted should have used '''value''' instead of 'value' for the cached values. The latter causes a synax error when the code is executed. T. |
From: Ian B. <ia...@co...> - 2001-04-09 06:32:25
|
A few quick notes about the generated code: Are you quoting any '''s in the strings? An alternative would be to use repr(), which will give you back a safe quoted string. You could speed this up by using string.join() instead of +. Concatenating strings is slower, since it joins the first two strings, then joins the next string to that, and so on. Just doing string.join([s1, s2, s3]) should be faster. Finally, I'm a little confused -- how did the translator know that nestedTemplate whas a nested template, but other things were callableNames? Tavis Rudd <ta...@ca...> wrote: > > > This is good. PSP is much more general than this > > template system. You'd no longer be able to unparse a > > document, for instance, and at some levels of the system > > there would be much more allowance for generality than > > necessary. This just makes the code harder to follow, > > and considerably harder to optimize. > > Have a look at the code it generates (see attachment). > It's not bytecompiled, so it's very easy to read. > > > I would also try to parse it to a list and interpret > > that, instead of translating it to code. I suspect it is > > just as fast to do the substitution to the list and join > > it as it is to translate the list to Python code and > > execute it -- either way you are doing about the same > > amount of work. The non-Python-code-translation way, > > though, would be more memory efficient and probably > > easier for others to read. > > I'm not sure how I could cache the name mappings in the way > I want with a list version. There must be a way though. > > > Or at least, it should be easy enough to code both and > > then you can compare speed. > > If I upload the latest code do you have time to try out a > list version of it? |
From: Tavis R. <ta...@ca...> - 2001-04-09 06:43:01
Attachments:
TemplateFiller.py
SkeletonPage.py
|
> Are you quoting any '''s in the strings? An alternative > would be to use repr(), which will give you back a safe > quoted string. That came to my mind, but I haven't done anything with it yet. How about repr( str( value ) ) then as not all the values are strings? > You could speed this up by using string.join() instead of > +. Concatenating strings is slower, since it joins the > first two strings, then joins the next string to that, > and so on. Just doing string.join([s1, s2, s3]) should > be faster. Good point, and very easy to do! Speed's not a huge issue though. It's cranking 20,000 copies of that output in 4 seconds of a single processor Athlon 600. > Finally, I'm a little confused -- how did the translator > know that nestedTemplate whas a nested template, but > other things were callableNames? Have a look at the _nameProcessor name processor method in BoundTemplate in the attachment. If you want to run it. Get www.calrudd.com/templates.tar.gz and run SkeletonPage from the command line. python SkeletonPage.py -h will give you the menu, with needs updating and gives options that no work without sprintf. |
From: Sasa Z. <sa...@sp...> - 2001-04-09 10:27:25
Attachments:
stpl.zip
|
Hi All, The discussion on this list started to introduce a new mini template programming language and, personally, I do not like this idea. This is a template system with simple templates. The meaning of simple in this case is "without any programming logic in them". If you like this idea then please try it out! It is based on PHPLib's template system and it is integrataed with WebKit's Page class. The TemplatePage class is subclass of Page and I tried to make it compatible with writeHeader/writeBody/writeFooter idiom. The basic idea is very similar to how you use WebKit's Page class. You define a SitePage (called master in attached example) and defaults in it. Then you define subclasses and so on... Every TemplatePage (sub)class contains set of properties (maybe better name is mappings). The writeHeader method actually writes value of the property "HEADER". The writeBody method writes value of the property "BODY". The writeFooter method writes value of the property "FOOTER". Property value is a string. There are two possible cases: 1. property value does not begin with "!". In this case the whole string is the value, 2. property value begins with an "!" (example "!dspHeader"). In this case the value of the property is the template ("dspHeader.html") Then template file is open, and every {TAG} in this template is considered like property name and is being replaced with its value according to rules 1. and 2. Also, before the {TAG}'s are substitued it is checked if a method with the same name as template exists and, if exists, it is called. This method is then supposed to do what is very specific for this template (for example take data from database and put values into the template). Every tag that still remains undefined after this method is replaced like a normal property (rules 1. and 2.) I have attached the implemementation with examples. After you unpack the file you have to edit config.py and to enter the path to the templates directory. Create a new context in application.config that points to the directory where you unpacked the example. Start WebKit and try it out. NOTE: this is an early version and possibly lot of things can be redesigned/reimplemented. Any idea is welcome! - Sasa |
From: Ian B. <ia...@co...> - 2001-04-09 20:09:32
|
"Sasa Zivkov" <sa...@sp...> wrote: > The discussion on this list started to introduce a new mini template > programming language and, personally, I do not like this idea. I think there is a validity to this -- there's just no definately place to stop once you've started adding programming constructs to the template language. *However*, there are significant problems with just having substitution. One example is a result set formatted as a table -- substitution can't represent the repeating rows. And then sometimes the result set will be empty and you'll want something else entirely (no <TABLE></TABLE>, plus extra text). You can't do this with substitution, because the Python would have to know to delete the table tags (or it would have to know to insert the table tags)... then you need an if clause. But what if the result set doesn't resolve to true/false? You have if clauses with expressions. Oh, it could go on forever. And it does! But you want to avoid that. Actually, avoiding that seems a general consensus. So I was thinking, how can you actually express everything you need to, while keeping a seperation between (most) HTML and the Python code? Then I realized the interaction between the template and the Python was asymmetric. The Python could do stuff to the template, but the template had no real way to talk back to the Python. What the template language needs -- or, at least, what needs to be used in conjuction with the template language -- is some way of defining a structured text document. Like maybe something like: <html> yada yada <!-- Here are the results --> {def resultSet} <table> {def resultRow} <tr><td>{productDescription}</td><td>{productPrice}</td></tr> {/def} </table> {/def} {def noResultSet} Sorry, there weren't any products that matched your search. {/def} yada yada </html> The Python code can provide data to fill in the template -- like productDescription and productPrice. But the page also provides values to the Python code -- resultSet, resultRow, and noResultSet. These will be conditionally included or repeated as the Python code dictates. The semantics of those values are completely arbitrary -- an agreement between the code and template. They are also fairly general -- as you do more things, you agree on more named pieces. There isn't any feature creep, because there is a firm seperation between data (in the template) and code (in the Python). This would be particularly useful in cases where *content*, not design, was being created by non-programmers. This is also an important situation that Zope is pretty good at, but Webware currently doesn't cover at all. Content contains a structured core of text, potentially with a bunch of junk around it (the properly formed HTML document that WYSIWYG editors demand), but often doesn't need substitutions. *Or*, it gets phrased as a substitution with <!--#include file="header.html"--> or something, which I think is totally lame, usually makes the WYSIWYG editors unhappy, and creates a dependency (that, say, header.html exists) that is unnecessary. Ian |
From: Sasa Z. <sa...@sp...> - 2001-04-10 10:35:52
Attachments:
stpl.tar.gz
|
> -----Original Message----- > From: Ian Bicking [mailto:ia...@co...] > Sent: 9. apríl 2001 20:09 > To: sa...@sp... > Cc: web...@li... > Subject: Re: [Webware-discuss] stpl - Simple Templates > > > "Sasa Zivkov" <sa...@sp...> wrote: > > The discussion on this list started to introduce a new mini template > > programming language and, personally, I do not like this idea. > > I think there is a validity to this -- there's just no definately > place to stop once you've started adding programming constructs to the > template language. > > *However*, there are significant problems with just having > substitution. One example is a result set formatted as a table -- > substitution can't represent the repeating rows. And then sometimes > the result set will be empty and you'll want something else entirely > (no <TABLE></TABLE>, plus extra text). You can't do this with > substitution, because the Python would have to know to delete the > table tags (or it would have to know to insert the table tags)... > then you need an if clause. But what if the result set doesn't > resolve to true/false? You have if clauses with expressions. Oh, it > could go on forever. And it does! In stpl one can avoid this by using the next template: <!-- BEGIN data --> <table> <!-- BEGIN row --> <tr><td>{TITLE}</td><td>{DATE></td></tr> <!-- END row --> </table> <!-- END data --> <!-- BEGIN no_data --> Sorry, no more items <!-- END no_data --> then in python code that uses this template you will kill (delete) either "data" or "no_data" block depending on if you have empty or non-empty result set. Blocks are not just for repeating but also for marking something that can optionally be hiden. > But you want to avoid that. Actually, avoiding that seems a general > consensus. So I was thinking, how can you actually express everything > you need to, while keeping a seperation between (most) HTML and the > Python code? > > Then I realized the interaction between the template and the Python > was asymmetric. The Python could do stuff to the template, but the > template had no real way to talk back to the Python. Absolutelly correct! > > What the template language needs -- or, at least, what needs to be > used in conjuction with the template language -- is some way of > defining a structured text document. Like maybe something like: > > <html> > yada yada > > <!-- Here are the results --> > > {def resultSet} > <table> > {def resultRow} > <tr><td>{productDescription}</td><td>{productPrice}</td></tr> > {/def} > </table> > {/def} > {def noResultSet} > Sorry, there weren't any products that matched your search. > {/def} > > yada yada > </html> What you proposed here is exactly what blocks are for in stpl :-) I modified examples in this attachment to demonstrate use of blocks to hide optional parts. Take a look at news.py method dspNewsList and dspnewslist.html template. In data/news.py you can try to return an empty result in order to display "no_data" block from dspnewslist.html. I am posting the stpl again since Ian reported it was corrupted. This time it is in tar.gz format but files inside are still in DOS (CR/LF) format Regards, - Sasa |
From: Tom S. <tom...@li...> - 2001-04-10 22:34:39
|
Sasa Zivkov wrote: > What you proposed here is exactly what blocks are for in stpl :-) > > I modified examples in this attachment to demonstrate use of blocks > to hide optional parts. Take a look at news.py method dspNewsList > and dspnewslist.html template. > In data/news.py you can try to return an empty result in order to display > "no_data" block from dspnewslist.html. > > I am posting the stpl again since Ian reported it was corrupted. > This time it is in tar.gz format but files inside are still in DOS (CR/LF) > format I gave your code a try. Works after some tweaks and is really simple to use. Nice proof of concept. Performancewise you lose a lot with many template pieces, because they are not cached (I lose around 30 request / second even for the simplest pages). Any chance to improve that? Your code does also not conform to the Webware Stile Guide (I had to learn that too, because Chuck is quite strict on it. Reading Webware code is much easier if everybody uses the same rules, so it's really worth the time). If you need advice, you'll get it :-) Also names like def dfltTplSubst(self, tpl_name): tpl_filename = tpl_name.lower() + ".html" tpl = template(self.path) tpl.file("T", tpl_filename) are not easy to understand (same for one character variable names ;-) Most methods need a short doc string (especially template.py). B.T.W. Plow = template? and what is Plow? Ignoring all this minor details, the result shows how easy it is to implement a simple template language. I could live with your solution (a performance/Caching fix would be nice though..). PlateKit from Tavis Rudd has other nice ideas implemented (I have to look at it more deeply). Is there a chance to combine the best of both worlds (+ Chucks ideas on that topic, + zebra?) and bring the template discussion to an end? -- Tom Schwaller http://www.linux-community.de |
From: Mike O. <ir...@ms...> - 2001-04-10 23:25:28
|
On Wed, Apr 11, 2001 at 12:41:40AM +0200, Tom Schwaller wrote: > B.T.W. Plow = template? and what is Plow? Plow was my original template class, which Sasa incorporated into his package as stpl/template.py . ("Plow" because it has the letters "pl" in it like "template".) I'm working on a new version of Plow which will be simpler and less PHP-like. For instance, instead of having multiple templates in one object, it will spawn a new object for the additional template. > PlateKit from Tavis Rudd has other nice ideas > implemented (I have to look at it more deeply). > Is there a chance to combine the best of both worlds > (+ Chucks ideas on that topic, + zebra?) and bring the template > discussion to an end? The problem is, each of us wants different things. Tavis and Chuck want robustness and display logic ("if" and "for" constructs). Sasa wants something similar to PHPLib's Template. And I want something simple and minimalistic. However, we are all borrowing code and ideas from each other, so there will be similarities. Whether one or all three of these gets packaged into Webware is unclear now--probably at least Tavis' will be. But all three will be publicly available. -- -Mike (Iron) Orr, ir...@ms... (if mail problems: ms...@ji...) http://mso.oz.net/ English * Esperanto * Russkiy * Deutsch * Espan~ol |
From: Sasa Z. <sa...@sp...> - 2001-04-11 09:54:59
|
> I gave your code a try. Works after some tweaks and is really > simple to use. Nice proof of concept. Performancewise you > lose a lot with many template pieces, because they are > not cached (I lose around 30 request / second even for > the simplest pages). Any chance to improve that? I want to improve that and I need a hint about how to do caching in Webware... will somebody help ? I am new to Webware :-) > Your code does also not conform to the Webware Stile Guide > (I had to learn that too, because Chuck is quite strict on it. > Reading Webware code is much easier if everybody uses the > same rules, so it's really worth the time). If you need advice, > you'll get it :-) Why not... here I am at Webware's home, so I am supposed to respect some house rules :-) Waiting for advice ... > Also names like > > def dfltTplSubst(self, tpl_name): > tpl_filename = tpl_name.lower() + ".html" > tpl = template(self.path) > tpl.file("T", tpl_filename) > > are not easy to understand (same for one character variable names ;-) > Most methods need a short doc string (especially template.py). I will add doc strings. I will also adopt to other Webware's coding standards once I know something about them. Regarding one character variable names there is a very good point at: http://www.lysator.liu.se/c/pikestyle.html But, any way if one character variable names are completely forbiden in Webware I will adopt to this. - Sasa |
From: Mike O. <ir...@ms...> - 2001-04-11 15:33:22
|
On Wed, Apr 11, 2001 at 09:52:11AM -0000, Sasa Zivkov wrote: > Regarding one character variable names there is a very good point at: > http://www.lysator.liu.se/c/pikestyle.html > > But, any way if one character variable names are completely forbiden in > Webware I will adopt to this. One-character variable names for private local variables are quite clear, especially if one tends to stick to well-known usages ( "for i in range(...)", "for k, v in dict.items()", x and y for coordinates, r and c for row and column, s for a temporary string which will be mutated several times, f for a file object, o or for an instance, etc.) If there are only one or two 1-character variables in a method, it's easy to see what they are and what they're for. If there are several, it becomes confusing. -- -Mike (Iron) Orr, ir...@ms... (if mail problems: ms...@ji...) http://mso.oz.net/ English * Esperanto * Russkiy * Deutsch * Espan~ol |
From: Chuck E. <ec...@mi...> - 2001-04-11 18:35:17
|
At 08:31 AM 4/11/2001 -0700, Mike Orr wrote: >If there are only one or two 1-character variables in a method, it's >easy to see what they are and what they're for. If there are several, >it becomes confusing. Often it grows to several and becomes confusing later, after the fact. Also, I love it when people do this: for i in names: print i :-) -Chuck |
From: Chuck E. <ec...@mi...> - 2001-04-11 18:32:15
|
At 09:52 AM 4/11/2001 +0000, Sasa Zivkov wrote: >Waiting for advice ... >I will add doc strings. I will also adopt to other Webware's coding >standards once I know something about them. Advice: start here: http://webware.sourceforge.net/Webware/Docs/StyleGuidelines.html I wrote this so I wouldn't have to rewrite it on the mailing list every time style issues came up. Certainly there can be more discussion afterwards, but that's the place to start. -Chuck |
From: Mike O. <ir...@ms...> - 2001-04-12 21:37:04
|
On Wed, Apr 11, 2001 at 12:41:40AM +0200, Tom Schwaller wrote: > Performancewise you > lose a lot with many template pieces, because they are > not cached (I lose around 30 request / second even for > the simplest pages). Any chance to improve that? Hi, Tom. What would you suggest to be cached and how would you go about implementing it? -- -Mike (Iron) Orr, ir...@ms... (if mail problems: ms...@ji...) http://mso.oz.net/ English * Esperanto * Russkiy * Deutsch * Espan~ol |
From: Chuck E. <ec...@mi...> - 2001-04-09 21:31:50
|
At 11:54 PM 4/8/2001 -0700, Tavis Rudd wrote: > > You could speed this up by using string.join() instead of > > +. Concatenating strings is slower, since it joins the > > first two strings, then joins the next string to that, > > and so on. Just doing string.join([s1, s2, s3]) should > > be faster. >Good point, and very easy to do! Speed's not a huge issue >though. It's cranking 20,000 copies of that output in 4 >seconds of a single processor Athlon 600. I'll just throw in some extra weight that when I benchmarked + vs. join() the differences were HUGE with join() being the clear victor. I actually never tested for really small things like a single "x+y+z". I was more concerned about longer concatenations and repetition. -Chuck |
From: Sam P. <sa...@dd...> - 2001-04-09 22:10:51
|
A good basic article on common performance issues in Python is at: <http://musi-cal.mojam.com/~skip/python/fastpython.html> Much of its content will be familiar to experienced programmers, but it has nice coverage of some basic string building issues. Better, it links to an essay by Guido on optimizing loops in Python: <http://www.python.org/doc/essays/list2str.html>. |
From: Tavis R. <ta...@ca...> - 2001-04-09 22:11:38
|
download http://www.calrudd.com/templates.tar.gz unpackage it, cd into the PlateKit dir, then run > python SkeletonPage.py -h to see how it works. It now generates compiled python code and uses string.join() instead of sprintf, so it's about 45 times faster. It's processing the SkeletonPage template over 10,000 times a second when called from the command-line, while dynamically refreshing the data. This is probably about the same speed pages using the writeHTML framework would yeild if run from the command-line. Even better performance can be acheived by doing timed refreshes of non-critical values. You can cache / cache-refresh the value of individual {names} embedded in your template definition, or you can run everything dynamically. Interestingly, using access methods is heaps faster than accessing raw instance vars at this stage. This'll probably change. Give it a shot and find the bugs. Tavis p.s. Chuck, you'll notice a few changes in NameMapper as well. |
From: Ian B. <ia...@co...> - 2001-04-09 07:06:47
Attachments:
AnotherTemplateThing.py
|
Tavis Rudd <ta...@ca...> wrote: > I'm not sure how I could cache the name mappings in the way > I want with a list version. There must be a way though. Yes, it just means altering the list. Of course, if (unlike this code) you didn't depend on odd-number-indices being dynamic then this would be much easier (but it isn't too hard as it is). There would be other ways one could mark an element of the list as something-to-be-substituted-later. I'm still avoid NamedAccess, because I just haven't looked at it yet. This version of the code does a trivial substitution that maps names to themselves. This is tested, unlike before. substituteParsedTemplate now uses string.join, which makes it way smaller. insertCachable does the caching I think you want (though maybe you wanted to do more?) Ian |
From: Ian B. <ia...@co...> - 2001-04-09 05:26:00
|
Tavis Rudd <ta...@ca...> wrote: > > Compiling to PSP is also an interesting idea. But maybe > > that's the same thing. > Someone suggested that, but it's the same thing with a much > more complicated startup. I'd like TemplateFiller objects > to be standalone and not rely on an external parser or > servlet factory. This should make it much easier to > integrate with Plow and others. This is good. PSP is much more general than this template system. You'd no longer be able to unparse a document, for instance, and at some levels of the system there would be much more allowance for generality than necessary. This just makes the code harder to follow, and considerably harder to optimize. > I've got a prototype working, where instead of building a > sprintf string at __init__ and running > self._sprintfTemplate % self._nameMappings() for each > retrieval, it translates all the code into a string > representing a function definition. It then executes this > definition using exec to create the function in the local > namespace ( self._compileTemplate's). I then map this > function to self.__str__() using the intancemethod() > function from the standard 'new' library. Thereafter, > every time the string method of the template is called this > function is executed and the output of the template is > returned. I would also try to parse it to a list and interpret that, instead of translating it to code. I suspect it is just as fast to do the substitution to the list and join it as it is to translate the list to Python code and execute it -- either way you are doing about the same amount of work. The non-Python-code-translation way, though, would be more memory efficient and probably easier for others to read. Or at least, it should be easy enough to code both and then you can compare speed. Ian |