From neel at mediapulse.com Thu Dec 5 06:42:29 2002 From: neel at mediapulse.com (Michael C. Neel) Date: Wed, 4 Dec 2002 14:42:29 -0500 Subject: [albatross-users] Two more issues Message-ID: I've come across two more issues with the toolkit (I know I've sent a lot of issues to the list, but that is in no way a bad mark on albatross; if it wasn't as awesome as it is I wouldn't be using it!) 1.) Setting multiple cookies. Currently it looks as if calls to ctx.request.write_header with the same header to set (in this case "Set-cookie") will overwrite each other, and write_header doesn't like tuples/lists. 2.) Al-if (and maybe other tags, I haven't tested) do not "see" session varaibles. For example if I have state as a session var, it will be displayed correctly on an al-input name="state" tage, but al-if expr="state == 'TN'" will error with no var names state. I don't know when you plan on a 1.02, but just as a convience, here's mike's short list... 1) the above (if they are not my errors of cource) 2) the al-input with a zero value (there was a patch on the list for this) 3) passing the status back as a result of a run (mod_python issue really) 4) ctx.req_equals using both image and image.x (a convienence really) 5) ctx.req_equals returning true only if the field exists is not blank, right now it will return true for empty fields on the second submission of the same page. Thanks, Mike From djc at object-craft.com.au Thu Dec 5 11:12:37 2002 From: djc at object-craft.com.au (Dave Cole) Date: 05 Dec 2002 11:12:37 +1100 Subject: [albatross-users] Two more issues In-Reply-To: References: Message-ID: >>>>> "Michael" == Michael C Neel writes: Michael> I've come across two more issues with the toolkit (I know Michael> I've sent a lot of issues to the list, but that is in no way Michael> a bad mark on albatross; if it wasn't as awesome as it is I Michael> wouldn't be using it!) Keep 'em coming. Michael> 1.) Setting multiple cookies. Currently it looks as if Michael> calls to ctx.request.write_header with the same header to set Michael> (in this case "Set-cookie") will overwrite each other, and Michael> write_header doesn't like tuples/lists. I have some code in CVS which changes the way that the headers are handled. The headers are now accumulated in an ordered dictionary in the request. It exposes an interface like this: set_header(name, value) del_header(name) get_header(name) The HeadersMixin (new execution context mixin) constructor does this: self.set_header('Pragma', 'no-cache') self.set_header('Content-Type', 'text/html') All of the overridden and extended write_headers() methods have been deleted. The session mixins now add the cookie header by simply doing self.set_header('Set-Cookie', value) I suppose the upshot of all this is that it give us the ability to accumulate extra cookie values before writing the headers out. Michael> 2.) Al-if (and maybe other tags, I haven't tested) do not Michael> "see" session varaibles. For example if I have state as a Michael> session var, it will be displayed correctly on an al-input Michael> name="state" tage, but al-if expr="state == 'TN'" will error Michael> with no var names state. Hmm... Does this mean that you are doing something like this: ctx.add_session_vars('blah') Without doing this: ctx.locals.blah = 42 If that is the case, Andrew and I have decided that it might make sense to make the add_session_vars() method create a ctx.locals value and set it to None if it does not currently exist in ctx.locals Michael> I don't know when you plan on a 1.02, but just as a Michael> convience, here's mike's short list... Michael> 1) the above (if they are not my errors of cource) They look like good additions to me. Michael> 2) the al-input with a zero value (there was a patch on the Michael> list for this) That patch is in CVS. It will be in the next release. Michael> 3) passing the status back as a result of a run (mod_python Michael> issue really) There is code in CVS which does this too. The Request constructors now do this: self.__status = 200 This establishes the default status which will be returned for the request. You can change it by calling the set_status() Request method at any stage. The Application run() method has been modified to return the status in the Request object. Michael> 4) ctx.req_equals using both image and image.x (a convienence Michael> really) That is a good feature to add. It reduces the surprise and confusion for image input fields. Michael> 5) ctx.req_equals returning true only if the field exists is Michael> not blank, right now it will return true for empty fields on Michael> the second submission of the same page. We are going to investigate this... - Dave -- http://www.object-craft.com.au From andrewm at object-craft.com.au Thu Dec 5 15:15:00 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Thu, 05 Dec 2002 15:15:00 +1100 Subject: [albatross-users] Two more issues In-Reply-To: Message from "Michael C. Neel" of "Wed, 04 Dec 2002 14:42:29 CDT." References: Message-ID: <20021205041500.18B4F3C510@coffee.object-craft.com.au> >5) ctx.req_equals returning true only if the field exists is not blank, >right now it will return true for empty fields on the second submission >of the same page. We've replaced req_equals (app.py, class AppContext) with the following, which should fix this problem. You can try the following, or wait for the next release: def req_equals(self, name): try: if self.request.field_value(name): return 1 except KeyError: pass return 0 -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From neel at mediapulse.com Fri Dec 6 05:25:28 2002 From: neel at mediapulse.com (Michael C. Neel) Date: Thu, 5 Dec 2002 13:25:28 -0500 Subject: [albatross-users] Two more issues Message-ID: > Michael> 2.) Al-if (and maybe other tags, I haven't tested) do not > Michael> "see" session varaibles. For example if I have state as a > Michael> session var, it will be displayed correctly on an al-input > Michael> name="state" tage, but al-if expr="state == 'TN'" will error > Michael> with no var names state. > > Hmm... Does this mean that you are doing something like this: > ctx.add_session_vars('blah') > > Without doing this: > ctx.locals.blah = 42 > > If that is the case, Andrew and I have decided that it might make > sense to make the add_session_vars() method create a ctx.locals value > and set it to None if it does not currently exist in ctx.locals > What I have is I start off with the add_session_vars('blah'), then of the first form, I have an input name="blah", which I make sure has a value then I send the user form2. On form2 I have an if "blah =='value'" which works fine on the first run, but should that form2 be displayed a second time I will get the error. I was able to work around this by add an input type="hidden" name="blah" to form2 so that blah was always "submitted". The above of adding a locals to set to None if it does not exist would save me on a lot of redundant code; I'd only need to explictly state a local if it was a list ( = [] ) or something simaliar. Mike From neel at mediapulse.com Fri Dec 6 06:24:35 2002 From: neel at mediapulse.com (Michael C. Neel) Date: Thu, 5 Dec 2002 14:24:35 -0500 Subject: [albatross-users] Two more issues Message-ID: Okay, I see what you meant. No, in the page_enter I did not initialize "blah", I only called ctx.add_session_vars("blah"), it was set though a form field and this doesn't appear to get the variable added to the session. It would be nice if this worked, but I can see the issue if blah was expected to be a dict or a list and was set to None instead of [] or {}. Still, I have a very large for with several fields that need to be in the session, and there is a lot of blah = blah1 = blah2 = None code in my page_enter, so I guess the lessor evil would be defaulting to none as you suggest, and I'll handle lists/dicts/objects myself. Thanks for all the help, Mike > -----Original Message----- > From: Michael C. Neel > Sent: Thursday, December 05, 2002 1:25 PM > To: Dave Cole > Cc: albatross-users at object-craft.com.au > Subject: RE: [albatross-users] Two more issues > > > > Michael> 2.) Al-if (and maybe other tags, I haven't tested) do not > > Michael> "see" session varaibles. For example if I have state as a > > Michael> session var, it will be displayed correctly on an al-input > > Michael> name="state" tage, but al-if expr="state == 'TN'" > will error > > Michael> with no var names state. > > > > Hmm... Does this mean that you are doing something like this: > > ctx.add_session_vars('blah') > > > > Without doing this: > > ctx.locals.blah = 42 > > > > If that is the case, Andrew and I have decided that it might make > > sense to make the add_session_vars() method create a > ctx.locals value > > and set it to None if it does not currently exist in ctx.locals > > > > What I have is I start off with the add_session_vars('blah'), then of > the first form, I have an input name="blah", which I make sure has a > value then I send the user form2. On form2 I have an if "blah > =='value'" which works fine on the first run, but should that form2 be > displayed a second time I will get the error. I was able to > work around > this by add an input type="hidden" name="blah" to form2 so > that blah was > always "submitted". > > The above of adding a locals to set to None if it does not exist would > save me on a lot of redundant code; I'd only need to explictly state a > local if it was a list ( = [] ) or something simaliar. > > Mike > _______________________________________________ > Albatross-users mailing list > Albatross-users at object-craft.com.au > https://www.object-craft.com.au/cgi-bin/mailman/listinfo/albat ross-users From andrewm at object-craft.com.au Fri Dec 6 12:34:16 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Fri, 06 Dec 2002 12:34:16 +1100 Subject: [albatross-users] User input sought In-Reply-To: Message from "Michael C. Neel" of "Thu, 05 Dec 2002 14:24:35 CDT." References: Message-ID: <20021206013416.7A1A73C510@coffee.object-craft.com.au> >>> Hmm... Does this mean that you are doing something like this: >>> ctx.add_session_vars('blah') >>> >>> Without doing this: >>> ctx.locals.blah = 42 >>> >>> If that is the case, Andrew and I have decided that it might make >>> sense to make the add_session_vars() method create a ctx.locals value >>> and set it to None if it does not currently exist in ctx.locals [...] >Okay, I see what you meant. No, in the page_enter I did not initialize >"blah", I only called ctx.add_session_vars("blah"), it was set though a >form field and this doesn't appear to get the variable added to the >session. > >It would be nice if this worked, but I can see the issue if blah was >expected to be a dict or a list and was set to None instead of [] or {}. >Still, I have a very large for with several fields that need to be in >the session, and there is a lot of blah = blah1 = blah2 = None >code in my page_enter, so I guess the lessor evil would be defaulting to >none as you suggest, and I'll handle lists/dicts/objects myself. As you say, this approach (add_session_vars setting undefined vars to None) fails where the application is expecting some other data type. While the application would have failed anyway, the proposed change may obscure the real cause of the problem. Another possible option is to have add_session_vars raise an exception if the variable doesn't already exist - the attraction of this approach is that you can raise the error right at the point where the bug exists. The downside is that it will break existing working code of the following form (although the fix is easy): ctx.add_session_vars('blah') ctx.locals.blah = 1 So - would the community prefer explicit over implicit (the Python philosophy) at the cost of a small amount of easily fixed breakage? -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From gnb at itga.com.au Fri Dec 6 12:57:41 2002 From: gnb at itga.com.au (Gregory Bond) Date: Fri, 06 Dec 2002 12:57:41 +1100 Subject: [albatross-users] User input sought In-Reply-To: Your message of Fri, 06 Dec 2002 12:34:16 +1100. Message-ID: <200212060157.MAA18526@lightning.itga.com.au> > Another possible option is to have add_session_vars raise an exception if > the variable doesn't already exist The problem I've run into a few times is having multiple paths into the current page, some of which set 'blah' into the session (with an appropriate value), some of which don't. So I do something like: ctx.add_session_vars('blah') try: ctx.locals.blah except AttributeError: ctx.locals.blah = 1 which is ugly and long_winded. Perhaps we could have a version of add_session_vars to also set default value. Perhaps something like ctx.add_session_vars_default('blah', 1) or, more complex, ctx.add_session_vars_default(('blah', 'blah2'), [1, None]) or, to turn it inside out a bit, ctx.add_session_vars_default(('blah', 1), ('blah2', None)) Or we could add a setdefault member to the Vars type: ctx.add_session_vars('blah') ctx.locals.setdefault('blah', 1) From andrewm at object-craft.com.au Fri Dec 6 13:08:32 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Fri, 06 Dec 2002 13:08:32 +1100 Subject: [albatross-users] User input sought In-Reply-To: Message from Gregory Bond of "Fri, 06 Dec 2002 12:57:41 +1100." <200212060157.MAA18526@lightning.itga.com.au> References: <200212060157.MAA18526@lightning.itga.com.au> Message-ID: <20021206020832.E60C83C510@coffee.object-craft.com.au> >> Another possible option is to have add_session_vars raise an exception if >> the variable doesn't already exist > >The problem I've run into a few times is having multiple paths into the >current page, some of which set 'blah' into the session (with an appropriate >value), some of which don't. > >So I do something like: > ctx.add_session_vars('blah') > try: > ctx.locals.blah > except AttributeError: > ctx.locals.blah = 1 >which is ugly and long_winded. Yep - Dave and I have been considering this - I also find myself doing something like the above all the time. I guess a setdefault() method for ctx.locals has the virtue of mirroring the setdefault() method for mapping types. I'm not sure I like the idea of poluting the locals namespace, however. I guess my perfered option is a default_session_vars() method that both registers and, if not already set, sets session vars. Should it set one variable at a time, or should it take tuples as args? I think I'd prefer the former - less chance of mistakes. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From cmiller at tigerbyte.com Fri Dec 6 13:41:59 2002 From: cmiller at tigerbyte.com (Clint Miller) Date: Thu, 5 Dec 2002 20:41:59 -0600 Subject: [albatross-users] Suggestion for pagesize, cols Message-ID: <200212052041.59523.cmiller@tigerbyte.com> Once I had my first albatross application working (in record time thanks to your clear and precise tool) I had the user types try it out and provide feedback. The first thing they wanted was a way to control the number of rows and columns displayed on a per-user basis. I cobbled together the following hack to tags.py to provide an expr_pagesize in the tag so that we didn't have to live with an absolute value in pagesize: --- albatross/tags.py Wed Sep 4 09:07:10 2002 +++ new-albatros/tags.py Thu Dec 5 20:18:06 2002 @@ -639,7 +639,7 @@ # be recreated if it already exists. name = self.get_attrib('iter') iter = None - if self.has_attrib('pagesize') or self.has_attrib('continue'): + if self.has_attrib('pagesize') or self.has_attrib('continue') or self.has_attrib('expr_pagesize'): iter = ctx.get_value(name) if iter is None: iter = ListIterator() @@ -657,6 +657,11 @@ ctx.add_session_vars(name) pagesize = int(self.get_attrib('pagesize')) iter.set_pagesize(pagesize) + elif self.has_attrib('expr_pagesize'): + ctx.add_session_vars(name) + t_pagesize = self.get_attrib('expr_pagesize') + pagesize = ctx.eval_expr(t_pagesize) + iter.set_pagesize(pagesize) # If CONTINUE if defined then the contents will flow on from # the previous use of the iterator if not self.has_attrib('continue'): Now I can read the number of rows desired by the user from a table and set it dynamically. There is something very similar for cols. Could we provide this kind of functionality in the distribution? Is this of interest to anyone? - Clint Miller From djc at object-craft.com.au Fri Dec 6 14:33:59 2002 From: djc at object-craft.com.au (Dave Cole) Date: 06 Dec 2002 14:33:59 +1100 Subject: [albatross-users] User input sought In-Reply-To: <20021206020832.E60C83C510@coffee.object-craft.com.au> References: <200212060157.MAA18526@lightning.itga.com.au> <20021206020832.E60C83C510@coffee.object-craft.com.au> Message-ID: >>>>> "Andrew" == Andrew McNamara writes: >>> Another possible option is to have add_session_vars raise an >>> exception if the variable doesn't already exist >> The problem I've run into a few times is having multiple paths >> into the current page, some of which set 'blah' into the session >> (with an appropriate value), some of which don't. >> >> So I do something like: ctx.add_session_vars('blah') try: >> ctx.locals.blah except AttributeError: ctx.locals.blah = 1 which is >> ugly and long_winded. Andrew> Yep - Dave and I have been considering this - I also find Andrew> myself doing something like the above all the time. I guess a Andrew> setdefault() method for ctx.locals has the virtue of mirroring Andrew> the setdefault() method for mapping types. I'm not sure I like Andrew> the idea of poluting the locals namespace, however. Andrew> I guess my perfered option is a default_session_vars() method Andrew> that both registers and, if not already set, sets session Andrew> vars. Should it set one variable at a time, or should it take Andrew> tuples as args? I think I'd prefer the former - less chance of Andrew> mistakes. Perhaps ctx.default_session_var(name, value) - Dave -- http://www.object-craft.com.au From gnb at itga.com.au Fri Dec 6 14:39:51 2002 From: gnb at itga.com.au (Gregory Bond) Date: Fri, 06 Dec 2002 14:39:51 +1100 Subject: [albatross-users] User input sought In-Reply-To: Your message of 06 Dec 2002 14:33:59 +1100. Message-ID: <200212060339.OAA27040@lightning.itga.com.au> > ctx.default_session_var(name, value) That'd do it for me. From djc at object-craft.com.au Fri Dec 6 15:11:23 2002 From: djc at object-craft.com.au (Dave Cole) Date: 06 Dec 2002 15:11:23 +1100 Subject: [albatross-users] Suggestion for pagesize, cols In-Reply-To: <200212052041.59523.cmiller@tigerbyte.com> References: <200212052041.59523.cmiller@tigerbyte.com> Message-ID: >>>>> "Clint" == Clint Miller writes: Clint> Once I had my first albatross application working (in record Clint> time thanks to your clear and precise tool) I had the user Clint> types try it out and provide feedback. The first thing they Clint> wanted was a way to control the number of rows and columns Clint> displayed on a per-user basis. I cobbled together the Clint> following hack to tags.py to provide an expr_pagesize in the Clint> tag so that we didn't have to live with an absolute Clint> value in pagesize: That is a nice addition. To be consistent with our other *expr attributes it would be better named pagesizeexpr (ugly, but consistent). - Dave -- http://www.object-craft.com.au From axel at kollmorgen.net Sat Dec 7 15:33:42 2002 From: axel at kollmorgen.net (Axel Kollmorgen) Date: Sat, 7 Dec 2002 05:33:42 +0100 Subject: [albatross-users] ImportError: cannot import name RandomModularSessionFileApp Message-ID: <00ce01c29da9$d55693d0$1665010a@condat.de> hi, when i change the "random" sample from a RandomModularSessionApp to a RandomModularSessionFileApp, i get the following error: Traceback (most recent call last): File "d:\pub\cgi\alsamp\random\random.py", line 2, in ? from albatross import RandomModularSessionFileApp File "D:\progs\develop\Python22\Lib\site-packages\albatross\__init__.py", line 12, in ? from albatross.sessionfile import * File "D:\progs\develop\Python22\Lib\site-packages\albatross\sessionfile.py", line 10, in ? import os, stat, sys, binascii, random, errno, struct File "d:\pub\cgi\alsamp\random\random.py", line 2, in ? from albatross import RandomModularSessionFileApp ImportError: cannot import name RandomModularSessionFileApp apparently a name clash problem - when i change random.py to bla.py, the problem has gone ("random" is a standard python module, isn't it?). i'm quite new to python so i don't know if this is a bug or just unfortunate. in any case, because others may run into the same problem, i'd suggest to either fix it, rename the sample dir or at least document it somehow. besides this, albatross looks like the thing i've been looking for (quite some time). thanks! -- ax Eventually, I think Chicago will be the most beautiful great city left in the world - Frank Lloyd Wright (1939) From andrewm at object-craft.com.au Tue Dec 10 11:06:47 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Tue, 10 Dec 2002 11:06:47 +1100 Subject: [albatross-users] ImportError: cannot import name RandomModularSessionFileApp In-Reply-To: Message from "Axel Kollmorgen" of "Sat, 07 Dec 2002 05:33:42 BST." <00ce01c29da9$d55693d0$1665010a@condat.de> References: <00ce01c29da9$d55693d0$1665010a@condat.de> Message-ID: <20021210000647.D5D0A3C510@coffee.object-craft.com.au> >when i change the "random" sample from a RandomModularSessionApp to a >RandomModularSessionFileApp, i get the following error: [...] >ImportError: cannot import name RandomModularSessionFileApp > > >apparently a name clash problem - when i change random.py to bla.py, the >problem has gone ("random" is a standard python module, isn't it?). i'm >quite new to python so i don't know if this is a bug or just >unfortunate. in any case, because others may run into the same problem, >i'd suggest to either fix it, rename the sample dir or at least document >it somehow. It looks like you're right - we'll rename it in the next release, and look at other ways we can avoid this problem in future (such as fiddling sys.path in the albatross __init__.py?). -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From djc at object-craft.com.au Thu Dec 12 16:02:38 2002 From: djc at object-craft.com.au (Dave Cole) Date: 12 Dec 2002 16:02:38 +1100 Subject: [albatross-users] Object Craft Python modules announcement Message-ID: Hello all. The purpose of this message is to collect some testimonials from the users of our Open Source software. We have recently joined Open Source Victoria (http://www.osv.org.au), which has the stated objective of being: "a new advocacy group formed to educate Victoria's (Australian) business and government leaders about the benefits of using Open Source software for both server and desktop environments." Your stories will be used to help the advocacy efforts of Open Source Victoria and more importantly, raise the profile of Open Source in general. (Of course it also helps us and our software stand out in the local market). Open Source advocacy obviously lacks the benefit of an enormous marketing budget, and therefore requires efforts at a grass roots level. Business and Government are generally very conservative and need to see that other organisations have successfully deployed Open Source products. Our products are: Albatross - A Toolkit for Highly Stateful Web Applications http://www.object-craft.com.au/projects/albatross/ CSV - A high performance CSV parser for Python http://www.object-craft.com.au/projects/csv/ MSSQL - A MS SQL Server module for Python http://www.object-craft.com.au/projects/mssql/ Paint - A fast, simple Python wrapper of libart, freetype, and libpng. http://www.object-craft.com.au/projects/paint/ sdk32 - A partial Python Wrap of the Win32 Platform SDK http://www.object-craft.com.au/projects/sdk32/ Sybase - A Sybase module for Python http://www.object-craft.com.au/projects/sybase/ It may come as a surprise, but we really have very little idea of who is using our software and what they are using it for. We would love to hear from you. Any contribution will be greatly appreciated. Please send email to: Mark Matthews Object Craft Pty Ltd. -- http://www.object-craft.com.au From gnb at itga.com.au Fri Dec 13 15:13:05 2002 From: gnb at itga.com.au (Gregory Bond) Date: Fri, 13 Dec 2002 15:13:05 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups Message-ID: <200212130413.PAA11166@lightning.itga.com.au> I'm confused. I can put definitions in a file, then do a load_template on that file, and the macros are available when I later do a run_template() in a page_display function. But if I put definitions in this file, then I have to do a run_template()_ in order to make the lookup work. This seems inconsistent. It certainly caused me great confusion! From andrewm at object-craft.com.au Fri Dec 13 18:33:43 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Fri, 13 Dec 2002 18:33:43 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: Message from Gregory Bond of "Fri, 13 Dec 2002 15:13:05 +1100." <200212130413.PAA11166@lightning.itga.com.au> References: <200212130413.PAA11166@lightning.itga.com.au> Message-ID: <20021213073343.C7F213C3AD@coffee.object-craft.com.au> >I can put definitions in a file, then do a load_template on that >file, and the macros are available when I later do a run_template() in a >page_display function. > >But if I put definitions in this file, then I have to do a >run_template()_ in order to make the lookup work. > >This seems inconsistent. It certainly caused me great confusion! Oops. I needed the macros registered at load time for something I was doing (previously they only registed at run time like lookups) - it didn't occur to me that any other tags needed the same treatment. I'll see what I can do for the next release (and if the patch is small, I'll mail it to the list). -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From andrewm at object-craft.com.au Fri Dec 13 19:10:00 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Fri, 13 Dec 2002 19:10:00 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: Message from Andrew McNamara of "Fri, 13 Dec 2002 18:33:43 +1100." <20021213073343.C7F213C3AD@coffee.object-craft.com.au> References: <200212130413.PAA11166@lightning.itga.com.au> <20021213073343.C7F213C3AD@coffee.object-craft.com.au> Message-ID: <20021213081000.BB8FA3C3AD@coffee.object-craft.com.au> >>I can put definitions in a file, then do a load_template on that >>file, and the macros are available when I later do a run_template() in a >>page_display function. >> >>But if I put definitions in this file, then I have to do a >>run_template()_ in order to make the lookup work. >> >>This seems inconsistent. It certainly caused me great confusion! > >Oops. I needed the macros registered at load time for something I >was doing (previously they only registed at run time like lookups) - >it didn't occur to me that any other tags needed the same treatment. >I'll see what I can do for the next release (and if the patch is small, >I'll mail it to the list). Try this patch (untested): --- albatross-1.01/albatross/tags.py Thu Sep 5 00:07:10 2002 +++ albatross-1.01-lookup/albatross/tags.py Fri Dec 13 19:08:57 2002 @@ -1026,6 +1026,7 @@ def __init__(self, ctx, filename, line_num, attribs): EnclosingTag.__init__(self, ctx, filename, line_num, attribs) self.assert_has_attrib('name') + ctx.register_lookup(self.get_attrib('name'), self) self.item_list = [] def append(self, tag): @@ -1035,7 +1036,6 @@ EnclosingTag.append(self, tag) def to_html(self, ctx): - ctx.register_lookup(self.get_attrib('name'), self) dict = {} for item in self.item_list: dict[item.eval_expr(ctx)] = item -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From gnb at itga.com.au Mon Dec 16 09:16:10 2002 From: gnb at itga.com.au (Gregory Bond) Date: Mon, 16 Dec 2002 09:16:10 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: Your message of Fri, 13 Dec 2002 19:10:00 +1100. Message-ID: <200212152216.JAA02317@lightning.itga.com.au> >Try this patch (untested): Alas, doesn't seem to be quite right..... File "/usr/local/lib/python2.1/site-packages/albatross/template.py", line 150, in to_html item.to_html(ctx) File "/usr/local/lib/python2.1/site-packages/albatross/tags.py", line 992, in to_html lookup.lookup_html(ctx, value) File "/usr/local/lib/python2.1/site-packages/albatross/tags.py", line 1045, in lookup_html item = self.item_dict.get(value, self.content) AttributeError: Lookup instance has no attribute 'item_dict' From andrewm at object-craft.com.au Mon Dec 16 11:51:23 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Mon, 16 Dec 2002 11:51:23 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: Message from Gregory Bond of "Mon, 16 Dec 2002 09:16:10 +1100." <200212152216.JAA02317@lightning.itga.com.au> References: <200212152216.JAA02317@lightning.itga.com.au> Message-ID: <20021216005123.6EB793C3AD@coffee.object-craft.com.au> >>Try this patch (untested): > >Alas, doesn't seem to be quite right..... > > File "/usr/local/lib/python2.1/site-packages/albatross/template.py", line 150, in to_html > item.to_html(ctx) > File "/usr/local/lib/python2.1/site-packages/albatross/tags.py", line 992, in to_html > lookup.lookup_html(ctx, value) > File "/usr/local/lib/python2.1/site-packages/albatross/tags.py", line 1045, in lookup_html > item = self.item_dict.get(value, self.content) >AttributeError: Lookup instance has no attribute 'item_dict' Ah - I think I see what you're doing - it's slightly different to my macro problem (and maybe macro's have the same bug). For my problem, I simply needed to know what resources were provided by a template (what macros it defined). In your case, you're defining a lookup after you're using it. It's not immediately obvious how I can make this work - the Lookup tag needs to know it's content. Hmmm - I could probably move the item_dict creation machinery from to_html to the first call of lookup_html. This will have to wait till I have more time (or you can try it yourself). -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From gnb at itga.com.au Mon Dec 16 12:14:35 2002 From: gnb at itga.com.au (Gregory Bond) Date: Mon, 16 Dec 2002 12:14:35 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: Your message of Mon, 16 Dec 2002 11:51:23 +1100. Message-ID: <200212160114.MAA06270@lightning.itga.com.au> > In your case, you're defining a lookup after you're using it. Hmm, I don't think so. At least, I'm not deliberately doing this! My App class does this: def create_context(self): ctx = AppContext(self) ctx.load_template('header.html') return ctx 'header.html' contains a bunch of definitions, and some definitions. So the macros and lookups should be defined before more-or-less anything else happens. Then in the page_display, I run_template() a file that uses these macros and lookups. The macros work, the lookups don't. If I change the create_context() to do ctx.run_template('header.html') then both the macros and lookups work. This is (cough) non-intuitive. From andrewm at object-craft.com.au Mon Dec 16 12:28:58 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Mon, 16 Dec 2002 12:28:58 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: Message from Gregory Bond of "Mon, 16 Dec 2002 12:14:35 +1100." <200212160114.MAA06270@lightning.itga.com.au> References: <200212160114.MAA06270@lightning.itga.com.au> Message-ID: <20021216012858.781DD3C3AD@coffee.object-craft.com.au> >> In your case, you're defining a lookup after you're using it. > >Hmm, I don't think so. At least, I'm not deliberately doing this! > >My App class does this: > > def create_context(self): > ctx = AppContext(self) > ctx.load_template('header.html') > return ctx > >'header.html' contains a bunch of definitions, and some > definitions. So the macros and lookups should be defined before more-or-less >anything else happens. > >Then in the page_display, I run_template() a file that uses these macros and >lookups. The macros work, the lookups don't. > >If I change the create_context() to do > ctx.run_template('header.html') >then both the macros and lookups work. This is (cough) non-intuitive. Ah - okay - similar scenario: the *contents* of the lookup are only registered at run time (the short patch I mailed only addressed the registering of the lookup name, not it's contents). Something like I mentioned in my previous message should work (but I don't have time to check right now). -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From gnb at itga.com.au Tue Dec 17 14:15:18 2002 From: gnb at itga.com.au (Gregory Bond) Date: Tue, 17 Dec 2002 14:15:18 +1100 Subject: [albatross-users] [patch] to run from the command line Message-ID: <200212170315.OAA06058@lightning.itga.com.au> It'd be nice to be able to run cgi albatross programs from the command line to check things like "is this a compilable python file". Much easier to check these things from the command line that fossicking though web error logs! Currently, if you try to run an albatross CGI from the command line, it errors inside albatross trying to get REQUEST_URI from the environment. This patch make the program at least run and produce useful output when run from the command line without a REQUEST_URI set. *** /home/lightning/gnb/src/albatross-1.01/albatross/cgiapp.py Tue Jul 30 17:33:49 2002 --- /usr/local/lib/python2.1/site-packages/albatross/cgiapp.py Tue Dec 17 14:11:04 2002 *************** *** 26,32 **** return self.__fields.keys() def get_uri(self): ! return os.environ['REQUEST_URI'] def get_servername(self): return os.environ['SERVER_NAME'] --- 26,35 ---- return self.__fields.keys() def get_uri(self): ! try: ! return os.environ['REQUEST_URI'] ! except KeyError: ! return '' # So we can run from the command line def get_servername(self): return os.environ['SERVER_NAME'] From andrewm at object-craft.com.au Tue Dec 17 16:47:08 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Tue, 17 Dec 2002 16:47:08 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: Message from Andrew McNamara of "Mon, 16 Dec 2002 12:28:58 +1100." <20021216012858.781DD3C3AD@coffee.object-craft.com.au> References: <200212160114.MAA06270@lightning.itga.com.au> <20021216012858.781DD3C3AD@coffee.object-craft.com.au> Message-ID: <20021217054708.9FFD13C3AD@coffee.object-craft.com.au> >>My App class does this: >> >> def create_context(self): >> ctx = AppContext(self) >> ctx.load_template('header.html') >> return ctx >> >>'header.html' contains a bunch of definitions, and some >> definitions. So the macros and lookups should be defined before more-or-less >>anything else happens. >> >>Then in the page_display, I run_template() a file that uses these macros and >>lookups. The macros work, the lookups don't. >> >>If I change the create_context() to do >> ctx.run_template('header.html') >>then both the macros and lookups work. This is (cough) non-intuitive. > >Ah - okay - similar scenario: the *contents* of the lookup are only >registered at run time (the short patch I mailed only addressed the >registering of the lookup name, not it's contents). Something like I >mentioned in my previous message should work (but I don't have time to >check right now). Hmmm - looking closer at the code, I don't think it would be valid to instanciate the lookups without a run. The reason for this is that the lookup key is the result of an eval - doing this eval at load time would be breaking the "rules". Possibly the eval could be lazy - essentially defer the eval until lookup_html is called for the first time (as I suggested before). I've just made the change in a sandbox, and it passes the unittests, but I'm not sure I like the change (the diff is against the CVS tree version - some fuzz may be required when applying to 1.01) - Dave - your thoughts? --- tags.py 15 Dec 2002 08:32:41 -0000 1.103 +++ tags.py 17 Dec 2002 05:45:51 -0000 @@ -1046,6 +1046,7 @@ def __init__(self, ctx, filename, line_num, attribs): EnclosingTag.__init__(self, ctx, filename, line_num, attribs) self.assert_has_attrib('name') + ctx.register_lookup(self.get_attrib('name'), self) self.item_list = [] def append(self, tag): @@ -1055,13 +1056,14 @@ EnclosingTag.append(self, tag) def to_html(self, ctx): - ctx.register_lookup(self.get_attrib('name'), self) - dict = {} - for item in self.item_list: - dict[item.eval_expr(ctx)] = item - self.item_dict = dict + pass def lookup_html(self, ctx, value): + if not hasattr(self, 'item_dict'): + dict = {} + for item in self.item_list: + dict[item.eval_expr(ctx)] = item + self.item_dict = dict item = self.item_dict.get(value, self.content) item.to_html(ctx) -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From gnb at itga.com.au Tue Dec 17 16:52:40 2002 From: gnb at itga.com.au (Gregory Bond) Date: Tue, 17 Dec 2002 16:52:40 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: Your message of Tue, 17 Dec 2002 16:47:08 +1100. Message-ID: <200212170552.QAA00818@lightning.itga.com.au> Hmm, OK, seems this is odder and harder than it looks on the surface. I'm not that fired up about the requirement for al-lookup tags to be run_template()'d and not just load_template()'d , but you'd need to be explicit about this (and the difference between load_template() and run_template(), which is still pretty hazy to me) in the manual. From gnb at itga.com.au Wed Dec 18 12:59:17 2002 From: gnb at itga.com.au (Gregory Bond) Date: Wed, 18 Dec 2002 12:59:17 +1100 Subject: [albatross-users] Handling user data error in forms Message-ID: <200212180159.MAA00427@lightning.itga.com.au> What are people doing to handle bad user data entered into forms? I've been doing things like: def page_process(self, ctx): if ctx.req_equals('submit'): try: d = check_date(ctx.locals.date) except DateError, e: ctx.locals.errmsg = "Unparsable date " + str(e) ctx.set_page('error') return but this simple scheme doesn't seem to work very well with the navigation (I'm using server-based sessions). It's not to bad for browser-based sessions, or simple apps with a single form on the front page, but breaks down if there are multiple forms in server-sessions. (In particular, the browser "back" button doesn't necessarily go where the user might think it ought.) Are there any better ways of handling this? Perhaps by letting exceptions percolate somewhere up the albatross stack? From andrewm at object-craft.com.au Wed Dec 18 13:51:25 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Wed, 18 Dec 2002 13:51:25 +1100 Subject: [albatross-users] Handling user data error in forms In-Reply-To: Message from Gregory Bond of "Wed, 18 Dec 2002 12:59:17 +1100." <200212180159.MAA00427@lightning.itga.com.au> References: <200212180159.MAA00427@lightning.itga.com.au> Message-ID: <20021218025125.AD49F3C3AD@coffee.object-craft.com.au> >but this simple scheme doesn't seem to work very well with the navigation >(I'm using server-based sessions). It's not to bad for browser-based >sessions, or simple apps with a single form on the front page, but breaks >down if there are multiple forms in server-sessions. (In particular, the >browser "back" button doesn't necessarily go where the user might think it >ought.) The "back" key and server sessions really don't mix at all well. This is one of the reasons I like the HiddenField sessions. One option we're considering is some complicated scheme involving embedding version numbers and maintaining an LRU of "forked" sessions (browsers with a "duplicate window" button cause related trouble). You can often structure your application so it's a little more forgiving of the occasional "back" (for example, making sure form controls are unique, and using a common page_process function), but it's a hard problem. The RandomPage application class was one answer to this problem, but causes grief of it's own (in particular, browsers flagging redirects on form submission as a security risk). -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From djc at object-craft.com.au Wed Dec 18 15:20:59 2002 From: djc at object-craft.com.au (Dave Cole) Date: 18 Dec 2002 15:20:59 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: <200212170552.QAA00818@lightning.itga.com.au> References: <200212170552.QAA00818@lightning.itga.com.au> Message-ID: >>>>> "Gregory" == Gregory Bond writes: Gregory> Hmm, OK, seems this is odder and harder than it looks on the Gregory> surface. Gregory> I'm not that fired up about the requirement for al-lookup Gregory> tags to be run_template()'d and not just load_template()'d , Gregory> but you'd need to be explicit about this (and the difference Gregory> between load_template() and run_template(), which is still Gregory> pretty hazy to me) in the manual. The manual has always been the big shortcoming with Albatross. One day we will get the time/money to invest a month or two on fixing up some of the problems in the documentation. - Dave -- http://www.object-craft.com.au From djc at object-craft.com.au Wed Dec 18 15:47:33 2002 From: djc at object-craft.com.au (Dave Cole) Date: 18 Dec 2002 15:47:33 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: <20021217054708.9FFD13C3AD@coffee.object-craft.com.au> References: <200212160114.MAA06270@lightning.itga.com.au> <20021216012858.781DD3C3AD@coffee.object-craft.com.au> <20021217054708.9FFD13C3AD@coffee.object-craft.com.au> Message-ID: > >>My App class does this: > >> > >> def create_context(self): > >> ctx = AppContext(self) > >> ctx.load_template('header.html') > >> return ctx > >> > >>'header.html' contains a bunch of definitions, and some > >> definitions. So the macros and lookups should be > >>defined before more-or-less anything else happens. Yes. The idea behind macros and lookups is that they are application wide resources. In order to have the resources available when they are needed you register them immediately after creating the execution context. This is sort of what you are doing above. class App(...): def create_context(self): ctx = AppContext(self) ctx.run_template_once('macros.html') The idea behind the "run_template_once" is that when you are running inside mod_python you only want to load and execute the macros for the first request served by that Apache child. Once registered the macros and lookups can be reused until the child exits. With that in mind, this is what happens. * Loading the template creates the tag tree and registers the name of the macros. * Running the template evaluates the expressions in the lookup items () creates the dictionary of content fragments associated with the lookup. It is important to note that the content in the lookup items is not evaluated at run time. * Using the lookup in an locates the lookup by name and uses the result of the expression in expr="..." to look up the item content dictionary. The content fragment returned is then executed *in the same context as the tag which used the lookup* Macros are similar. The expanded content is evaluated in the context of the macro user, not the context of where the macro was defined. Normal template processing only has two phases; load, and execute. Lookups and macros have three phases; load, register, and execute. The register phase occurs when you run_template(). The execute phase occurs when you use the lookup or macro in another template. > Hmmm - looking closer at the code, I don't think it would be valid > to instanciate the lookups without a run. The reason for this is > that the lookup key is the result of an eval - doing this eval at > load time would be breaking the "rules". The rules are a bit tricky. I can't see why this wouldn't work though. > Possibly the eval could be lazy - essentially defer the eval until > lookup_html is called for the first time (as I suggested > before). I've just made the change in a sandbox, and it passes the > unittests, but I'm not sure I like the change (the diff is against > the CVS tree version - some fuzz may be required when applying to > 1.01) - Dave - your thoughts? The eval could possibly be lazy. I think if you are using lookup expressions that resolve to different values for different requests then you are going to be surprised at some point anyway... > --- tags.py 15 Dec 2002 08:32:41 -0000 1.103 > +++ tags.py 17 Dec 2002 05:45:51 -0000 > @@ -1046,6 +1046,7 @@ > def __init__(self, ctx, filename, line_num, attribs): > EnclosingTag.__init__(self, ctx, filename, line_num, attribs) > self.assert_has_attrib('name') > + ctx.register_lookup(self.get_attrib('name'), self) > self.item_list = [] > > def append(self, tag): > @@ -1055,13 +1056,14 @@ > EnclosingTag.append(self, tag) > > def to_html(self, ctx): > - ctx.register_lookup(self.get_attrib('name'), self) > - dict = {} > - for item in self.item_list: > - dict[item.eval_expr(ctx)] = item > - self.item_dict = dict > + pass > > def lookup_html(self, ctx, value): > + if not hasattr(self, 'item_dict'): > + dict = {} > + for item in self.item_list: > + dict[item.eval_expr(ctx)] = item > + self.item_dict = dict > item = self.item_dict.get(value, self.content) > item.to_html(ctx) The patch looks fine to me. Give it a shot and see what breaks. - Dave -- http://www.object-craft.com.au From djc at object-craft.com.au Wed Dec 18 16:18:41 2002 From: djc at object-craft.com.au (Dave Cole) Date: 18 Dec 2002 16:18:41 +1100 Subject: [albatross-users] load_template vs run_template, macros vs lookups In-Reply-To: <200212160114.MAA06270@lightning.itga.com.au> References: <200212160114.MAA06270@lightning.itga.com.au> Message-ID: > > In your case, you're defining a lookup after you're using it. > Hmm, I don't think so. At least, I'm not deliberately doing this! > > My App class does this: > > def create_context(self): > ctx = AppContext(self) > ctx.load_template('header.html') > return ctx > > 'header.html' contains a bunch of definitions, and some > definitions. So the macros and lookups should be > defined before more-or-less anything else happens. > > Then in the page_display, I run_template() a file that uses these > macros and lookups. The macros work, the lookups don't. > > If I change the create_context() to do > ctx.run_template('header.html') > then both the macros and lookups work. This is (cough) non-intuitive. The way it works is non-intuitive but useful. Definitely an area where the documentation could be improved :-) - Dave -- http://www.object-craft.com.au From bdhruva at gmx.net Thu Dec 19 16:31:12 2002 From: bdhruva at gmx.net (Dhruva B. Reddy) Date: Wed, 18 Dec 2002 22:31:12 -0700 Subject: [albatross-users] Automatically Send HTTP Request Message-ID: <20021219053112.GF435@greatspacetoaster> Hello, I am adding the functionality to collect payments to an Albatross-powered website, using PayPal's Instant Payment Notification (IPN) service. The contract goes like this: 1. Customer is directed to PayPal to log in and authorize payment. 2. PayPal sends a POST request to the application. 3. The application must automatically resend that request back to PayPal, and process the response. It seems kludgy to me (as opposed to PayPal doing this as a true web service), but I don't see any way around it. Have any of you done something like this before? Thanks, Dhruva -- "Advice is what we ask for when we already know the answer but wish we didn't." Erica Jong (b. 1942); US author From gnb at itga.com.au Thu Dec 19 18:20:37 2002 From: gnb at itga.com.au (Gregory Bond) Date: Thu, 19 Dec 2002 18:20:37 +1100 Subject: [albatross-users] Use with mod_python 3 / apache2? Message-ID: <200212190720.SAA09498@lightning.itga.com.au> I wanted to play around with mod_python, so I downloaded and installed apache2 and mod_python 3.0.1. But albatross doesn't seem to work, because albatross does from mod_python import utils which fails, because mod_python.utils does import _apache which fails, and there ain't no such file as _apache., tho there is a _apachemodule.o file containing python stuff. This looks like a monster bug in the mod_python build environment, but before I take this further has anyone done albatross / mod_python 3.0.1 and made it work? From neel at mediapulse.com Fri Dec 20 02:10:58 2002 From: neel at mediapulse.com (Michael C. Neel) Date: Thu, 19 Dec 2002 10:10:58 -0500 Subject: [albatross-users] Use with mod_python 3 / apache2? Message-ID: I'm running albatross under beta 3 of mod_python (haven't upgraded yet) without problems. This sounds like a mod_python issue - did you check mod_python by itself and albatross in cgi mode? Mike > -----Original Message----- > From: Gregory Bond [mailto:gnb at itga.com.au] > Sent: Thursday, December 19, 2002 2:21 AM > To: albatross-users at object-craft.com.au > Subject: [albatross-users] Use with mod_python 3 / apache2? > > > I wanted to play around with mod_python, so I downloaded and > installed apache2 > and mod_python 3.0.1. But albatross doesn't seem to work, > because albatross > does > from mod_python import utils > which fails, because mod_python.utils does > import _apache > which fails, and there ain't no such file as > _apache. python>, tho there is a _apachemodule.o file containing python stuff. > > This looks like a monster bug in the mod_python build > environment, but before I > take this further has anyone done albatross / mod_python > 3.0.1 and made it > work? > > > > _______________________________________________ > Albatross-users mailing list > Albatross-users at object-craft.com.au > https://www.object-craft.com.au/cgi-bin/mailman/listinfo/albat ross-users From neel at mediapulse.com Fri Dec 20 02:13:07 2002 From: neel at mediapulse.com (Michael C. Neel) Date: Thu, 19 Dec 2002 10:13:07 -0500 Subject: [albatross-users] Automatically Send HTTP Request Message-ID: I've done stuff like this befire, using the urllib that comes with python, and passing the resulting object to a ctx.locals. var for use in the template. Take a look at urllib in the module docs on the python website, I think it's what you are looking for. Mike > -----Original Message----- > From: Dhruva B. Reddy [mailto:bdhruva at gmx.net] > Sent: Thursday, December 19, 2002 12:31 AM > To: Albatross User's List > Subject: [albatross-users] Automatically Send HTTP Request > > > Hello, > > I am adding the functionality to collect payments to an > Albatross-powered website, using PayPal's Instant Payment Notification > (IPN) service. The contract goes like this: > > 1. Customer is directed to PayPal to log in and authorize > payment. > 2. PayPal sends a POST request to the application. > 3. The application must automatically resend that request back > to PayPal, and process the response. > > It seems kludgy to me (as opposed to PayPal doing this as a true web > service), but I don't see any way around it. Have any of you done > something like this before? > > Thanks, > Dhruva > -- > "Advice is what we ask for when we already know the answer but wish > we didn't." Erica Jong (b. 1942); US author > > _______________________________________________ > Albatross-users mailing list > Albatross-users at object-craft.com.au > https://www.object-craft.com.au/cgi-bin/mailman/listinfo/albat ross-users From gnb at itga.com.au Fri Dec 20 12:24:12 2002 From: gnb at itga.com.au (Gregory Bond) Date: Fri, 20 Dec 2002 12:24:12 +1100 Subject: [albatross-users] Use with mod_python 3 / apache2? In-Reply-To: Your message of Thu, 19 Dec 2002 18:20:37 +1100. Message-ID: <200212200124.MAA21954@lightning.itga.com.au> I wrote: > from mod_python import utils > which fails, because mod_python.utils does > import _apache > which fails, This is apparently normal. It is not possible to import mod_python (and hence albatross programs that use albatross.apacheapp) from the command line or indeed any context outside an apache mod_python invocation, as the _apache module is provided by the mod_python code inside apache. I'm now up and running. Thanks everyone for the comments. From john at totten.com Sat Dec 21 20:56:46 2002 From: john at totten.com (John Totten) Date: Sat, 21 Dec 2002 00:56:46 -0900 Subject: [albatross-users] Initialisation Message-ID: <200212210056.46496.john@totten.com> assumes that the user starts at the root node and builds a tree as they drill down. Is it possible to open a tree with n.deapth(num) already loaded into the session variables programmatically? This would allow a child in its context to be displayed to the user in response to their enquiry instead of a less than helpful root node. The other parts of the tree would still be automaticallly built by the user if they branch out from higher nodes. From djc at object-craft.com.au Sat Dec 21 23:21:56 2002 From: djc at object-craft.com.au (Dave Cole) Date: 21 Dec 2002 23:21:56 +1100 Subject: [albatross-users] Initialisation In-Reply-To: <200212210056.46496.john@totten.com> References: <200212210056.46496.john@totten.com> Message-ID: >>>>> "John" == John Totten writes: John> assumes that the user starts at the root node and John> builds a tree as they drill down. Is it possible to open a tree John> with n.deapth(num) already loaded into the session variables John> programmatically? This would allow a child in its context to be John> displayed to the user in response to their enquiry instead of a John> less than helpful root node. The other parts of the tree would John> still be automaticallly built by the user if they branch out John> from higher nodes. The tag is deliberately fairly dumb in order to avoid placing limitations on the kind of data that you might want to format using the tag. Having said that we have been thinking that there should be more support in the tag for the kind of requirement you have mentioned. Andrew, Ben, and I have been talking about the interface that we should add to the LazyTreeIterator for the next release. Nothing much has been agreed upon yet. One of the biggest limiting factors is that Albatross assumes very little about the tree structured data. For a non-lazy loaded tree Albatross only looks for a children attribute in each node. If the children attribute is present then the node is a parent node and the attribute is assumed to be a sequence of child nodes. If the children attribute is not present the node is a leaf node. For lazy loaded trees Albatross requires two methods be implemented. load_children(ctx) is called by Albatross when it wants your program to load the children of a particular node. albatross_alias() is called to obtain a unique string which identifies the node. This string is used in the LazyTreeIterator to record which nodes are selected and which are open. When the LazyTreeIterator loads the children of a node (via load_children()) it sets the children_loaded attribute of that node. As you have mentioned "drill down" I assume you are talking about a lazy loaded tree (non-lazy loaded trees are rendered fully expanded). In our applications where we have used lazy loaded trees we have written application code to partially open the tree and preselect nodes. For example, if you wanted to be able to remember the state of the tree and restore it next time a user connected to the application, you would probably have something like this: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - from myapp import utils def page_process(ctx): if ctx.req_equals(...): utils.restore_tree(ctx) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Then in myapp.utils you would have something like this: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - from albatross import LazyTreeIterator def restore_tree(ctx): # Create the tree root and fetch the previous state of the tree. ctx.locals.root = create_tree_root(ctx) open_aliases, selected_alias = previous_tree_state(ctx) # Create the tree iterator used in the HTML template. We must # also place the iterator into the session because Albatross will # assume this has been done when it notices that the iterator # already exists. ctx.locals.hn = LazyTreeIterator() ctx.add_session_vars('hn') # Pre-load the children of all open tree nodes. walk_children(ctx, ctx.locals.root, open_aliases) # Place the previous state of the tree into the iterator so the # display will be correct. ctx.locals.hn.set_open_aliases(open_aliases) ctx.locals.hn.set_selected_aliases([selected_alias]) def walk_children(ctx, node, open_aliases): node.load_children(ctx) node.children_loaded = 1 for child in node.children: if child.albatross_alias() in open_aliases: walk_children(ctx, child, open_aliases) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Note that the above only uses node aliases. If you wanted to do something more sophisticated in your application which used attributes which were specific to your application, then your walk_children() would need to know how to locate nodes via those attributes. It would build up a list of node aliases which could then be passed to the set_selected_aliases() method of the LazyTreeIterator. Hope this has not further confused you. - Dave -- http://www.object-craft.com.au From djc at object-craft.com.au Sat Dec 21 23:29:23 2002 From: djc at object-craft.com.au (Dave Cole) Date: 21 Dec 2002 23:29:23 +1100 Subject: [albatross-users] Initialisation In-Reply-To: References: <200212210056.46496.john@totten.com> Message-ID: I forgot to add something... Tree data which is lazy loaded should be placed into the session else you are likely to get all sorts of confusing problems. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - from albatross import LazyTreeIterator def restore_tree(ctx): # Create the tree root and fetch the previous state of the tree. ctx.locals.root = create_tree_root(ctx) ctx.add_session_vars('root') : : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Dave -- http://www.object-craft.com.au From gnb at itga.com.au Mon Dec 23 12:21:54 2002 From: gnb at itga.com.au (Gregory Bond) Date: Mon, 23 Dec 2002 12:21:54 +1100 Subject: [albatross-users] Small patch needed for ctx.redirect() & mod_python 3.0.1 Message-ID: <200212230121.MAA14460@lightning.itga.com.au> I tried using ctx.redirect() under mod_python and it failed. The following patch fixes it. I don't know if this is a mod_python 2.7->3.0 change or just a bug in albatross. hellcat$ diff -u albatross-1.01/albatross/apacheapp.py /usr/local/lib/python2.2/site-packages/albatross/apacheapp.py --- albatross-1.01/albatross/apacheapp.py Tue Jul 30 17:33:49 2002 +++ /usr/local/lib/python2.2/site-packages/albatross/apacheapp.py Mon Dec 23 12:02:11 2002 @@ -31,7 +31,7 @@ return self.__req.uri def get_servername(self): - return self.__req.connection.server.server_hostname + return self.__req.server.server_hostname def get_header(self, name): if self.__req.headers_in.has_key(name): hellcat$ From djc at object-craft.com.au Mon Dec 23 12:27:49 2002 From: djc at object-craft.com.au (Dave Cole) Date: 23 Dec 2002 12:27:49 +1100 Subject: [albatross-users] Small patch needed for ctx.redirect() & mod_python 3.0.1 In-Reply-To: <200212230121.MAA14460@lightning.itga.com.au> References: <200212230121.MAA14460@lightning.itga.com.au> Message-ID: >>>>> "Gregory" == Gregory Bond writes: Gregory> I tried using ctx.redirect() under mod_python and it failed. Gregory> The following patch fixes it. I don't know if this is a Gregory> mod_python 2.7->3.0 change or just a bug in albatross. I assume you are running mod_python 3.0? It has been a while since we upgraded our mod_python, so it could be either :-) - Dave -- http://www.object-craft.com.au From gnb at itga.com.au Mon Dec 23 12:50:54 2002 From: gnb at itga.com.au (Gregory Bond) Date: Mon, 23 Dec 2002 12:50:54 +1100 Subject: [albatross-users] mod_python and global namespace Message-ID: <200212230150.MAA15633@lightning.itga.com.au> When running as a CGI, I can access the script global namespace from templates, so I can do things like: Under mod_python(3.0.1), this doesn't work, and I have to import globals into ctx.locals to make them available. Is this: - An inevitable consequence of using mod_python - Exploiting an unexpected bug in the CGI case - a bug in albatross.apacheapp ? From djc at object-craft.com.au Mon Dec 23 13:33:24 2002 From: djc at object-craft.com.au (Dave Cole) Date: 23 Dec 2002 13:33:24 +1100 Subject: [albatross-users] mod_python and global namespace In-Reply-To: <200212230150.MAA15633@lightning.itga.com.au> References: <200212230150.MAA15633@lightning.itga.com.au> Message-ID: > When running as a CGI, I can access the script global namespace from > templates, so I can do things like: > > > Under mod_python(3.0.1), this doesn't work, and I have to import > globals into ctx.locals to make them available. > > Is this: > - An inevitable consequence of using mod_python > - Exploiting an unexpected bug in the CGI case > - a bug in albatross.apacheapp It looks like it is a bug in Albatross. What Albatross tries to do is create an environment for expression evaluation such that eval(expr, globals, locals) maps globals to the global namespace of the module which called run_template() and locals to ctx.locals. The method for locating the global namespace (context._caller_globals()) is not working in your case. At the moment _caller_globals() just counts back a number of stack frames. It should probably be modified to keep going back past a named function. So, AppContext.run_template() would look something like this: def run_template(self, name): templ = self.app.load_template(name) self.set_globals(_caller_globals('run_template')) templ.to_html(self) Then _caller_globals() would have to be something like this: def caller_globals(name): try: raise ZeroDivisionError except ZeroDivisionError: frame = sys.exc_traceback.tb_frame while frame.f_code.co_name != name: frame = frame.f_back while frame.f_code.co_name == name: frame = frame.f_back return frame.f_globals - Dave -- http://www.object-craft.com.au From djc at object-craft.com.au Mon Dec 23 13:47:58 2002 From: djc at object-craft.com.au (Dave Cole) Date: 23 Dec 2002 13:47:58 +1100 Subject: [albatross-users] mod_python and global namespace In-Reply-To: References: <200212230150.MAA15633@lightning.itga.com.au> Message-ID: >>>>> "Dave" == Dave Cole writes: Dave> It looks like it is a bug in Albatross. What Albatross tries to Dave> do is create an environment for expression evaluation such that Dave> eval(expr, globals, locals) Dave> maps globals to the global namespace of the module which called Dave> run_template() and locals to ctx.locals. The method for Dave> locating the global namespace (context._caller_globals()) is not Dave> working in your case. [snip] If I send you a patch which implements my proposed fix and a shirtload of enhancements since 1.01 would you be willing to try it out? We keep wanting to make a new release but do not get the time to bring the documentation up to date with our changes. - Dave -- http://www.object-craft.com.au From djc at object-craft.com.au Mon Dec 23 13:50:03 2002 From: djc at object-craft.com.au (Dave Cole) Date: 23 Dec 2002 13:50:03 +1100 Subject: [albatross-users] mod_python and global namespace In-Reply-To: References: <200212230150.MAA15633@lightning.itga.com.au> Message-ID: >>>>> "Dave" == Dave Cole writes: >>>>> "Dave" == Dave Cole writes: Dave> It looks like it is a bug in Albatross. What Albatross tries to Dave> do is create an environment for expression evaluation such that Dave> eval(expr, globals, locals) Dave> maps globals to the global namespace of the module which called Dave> run_template() and locals to ctx.locals. The method for Dave> locating the global namespace (context._caller_globals()) is not Dave> working in your case. Dave> [snip] Dave> If I send you a patch which implements my proposed fix and a Dave> shirtload of enhancements since 1.01 would you be willing to try Dave> it out? Dave> We keep wanting to make a new release but do not get the time to Dave> bring the documentation up to date with our changes. Oops!!! That was supposed to go only to Greg. Sorry about that. - Dave -- http://www.object-craft.com.au From gnb at itga.com.au Mon Dec 23 15:02:10 2002 From: gnb at itga.com.au (Gregory Bond) Date: Mon, 23 Dec 2002 15:02:10 +1100 Subject: [albatross-users] Handy mod_python hint Message-ID: <200212230402.PAA23747@lightning.itga.com.au> You can run a single Albatross program either as a normal CGI, as a native mod_python script, or as a CGI under mod_python using mod_python's cgihandler, with a trick like this: try: os.environ['GATEWAY_INTERFACE'] cgi = 1 except: cgi = 0 from albatross import SimpleSessionFileApp, SessionFileAppContext if cgi: from albatross.cgiapp import Request else: from albatross.apacheapp import Request # Page classes, application/context objects, etc here app = App() def handler(req): '''Called from mod_python - turn a mod_python req into an Albatross Request''' return do_handler(Request(req)) def do_handler(r): '''Called with an Albatross Request object''' return app.run(r) if cgi: do_handler(Request()) From djc at object-craft.com.au Mon Dec 23 15:14:14 2002 From: djc at object-craft.com.au (Dave Cole) Date: 23 Dec 2002 15:14:14 +1100 Subject: [albatross-users] Handy mod_python hint In-Reply-To: <200212230402.PAA23747@lightning.itga.com.au> References: <200212230402.PAA23747@lightning.itga.com.au> Message-ID: > You can run a single Albatross program either as a normal CGI, as a > native mod_python script, or as a CGI under mod_python using > mod_python's cgihandler, with a trick like this: > > try: > os.environ['GATEWAY_INTERFACE'] > cgi = 1 > except: > cgi = 0 > > from albatross import SimpleSessionFileApp, SessionFileAppContext > if cgi: > from albatross.cgiapp import Request > else: > from albatross.apacheapp import Request > > # Page classes, application/context objects, etc here > > app = App() > > def handler(req): > '''Called from mod_python - turn a mod_python req into an Albatross Request''' > return do_handler(Request(req)) > > def do_handler(r): > '''Called with an Albatross Request object''' > return app.run(r) > > if cgi: > do_handler(Request()) That is seriously cool :-) - Dave -- http://www.object-craft.com.au