From andrewm at object-craft.com.au Thu Jun 6 16:06:27 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Thu, 06 Jun 2002 16:06:27 +1000 Subject: [albatross-users] ModularSessionFileApp and windows In-Reply-To: Your message of "Fri, 05 Apr 2002 08:21:28 +0200." Message-ID: <20020606060627.79E7538F50@coffee.object-craft.com.au> >Has anyone used ModularSessionFileApp on a windows platform? >I have had to do the following to make it work. > >in sessionfile.py >add : import struct > >in albatross directory >rename random.py to Random.py > >in albatross __init__.py > >change >from random import * >to >from Random import * These two problems should be fixed in the next release, which should occur before the end of the month. If anyone else has anything that needs to be fixed, now is the time to let us know. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From dkuhlman at cutter.rexx.com Wed Jun 19 10:31:41 2002 From: dkuhlman at cutter.rexx.com (Dave Kuhlman) Date: Tue, 18 Jun 2002 17:31:41 -0700 Subject: [albatross-users] Session management how-to? Message-ID: <20020618173140.A84176@cutter.rexx.com> I'm groping my way through Albatross -- reading the doc, reading the code, building sample apps. Albatross looks very much like the kind tool that I'm looking for, specifically a Web app server that can be used as a framework for building more specialized application servers. However, I need a clue or two about how to manage sessions in a session based application. I'm using SimpleSessionFileApp and SessionFileAppContext. Since I'm using a page object application, I've created a .py file with one class for each page. So, I have these questions: 1. How and where do I create a new session. Do I need to? I'm guessing I should put that code in the class for the start page. What code and where? In the page_enter method? In the page_process method? 2. How and where do I delete (remove?) a session. I'm guessing I should put that code in the class for the last page of the application. What code and where? In the page_display method (and after ctx.run_template())? 3. And what does each page class need to do in order to ensure that it is using the correct session data/state for the current request? What I'm looking for is something like the following: If you want to implement a application based on PageObjectMixin, SimpleSessionFileApp, and SessionFileAppContext, then (1) create the session by putting this code in the X method of the class for the start page; (2) delete/remove the session by putting this code in the Y method of the class for the last page; etc. I need to understand the order and conditions under which page object methods page_process, page_enter, page_leave, and page_display are called. Trace methods in my app and reading section "4.1 Albatross Application Model" of the manual have me less than enlightened. Is there any place I can look for more explanation on the processing model that Albatross follows? Thanks in advance for help. - Dave -- Dave Kuhlman dkuhlman at rexx.com http://www.rexx.com/~dkuhlman From andrewm at object-craft.com.au Wed Jun 19 11:11:48 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Wed, 19 Jun 2002 11:11:48 +1000 Subject: [albatross-users] Session management how-to? In-Reply-To: Your message of "Tue, 18 Jun 2002 17:31:41 MST." <20020618173140.A84176@cutter.rexx.com> Message-ID: <20020619011148.3B6FF38F5A@coffee.object-craft.com.au> >However, I need a clue or two about how to manage sessions in a >session based application. I'm using SimpleSessionFileApp and >SessionFileAppContext. Since I'm using a page object application, >I've created a .py file with one class for each page. So, I have >these questions: > >1. How and where do I create a new session. Do I need to? I'm > guessing I should put that code in the class for the start > page. What code and where? In the page_enter method? In the > page_process method? If the request from the browser contains information about an existing session, that session is used, otherwise a new one is created. So, in the case of the session file classes, SessionFileContextMixin looks for a cookie containing the session id in the browser request, and retrieves the appropriate session from the filesystem (or the session server, in the case of the session server classes). In the case of the hidden field classes, the session is a pickled and signed hidden form field. Your cgi script might contain something like this (note that I haven't tested this - it may contain typos, but should give you the idea): class App(albatross.SimpleSessionFileApp): def __init__(self): albatross.SimpleSessionFileApp.__init__(self, base_url = 'app.py', template_path = 'templates', start_page = 'login', secret = '*secret*', session_appid = 'app', session_dir = '/tmp/app') def create_context(self): ctx = albatross.SessionFileAppContext(self) # Load some macro templates here, if you like # ctx.run_template_once('macrostuff.html') return ctx if __name__ == '__main__': app = App() app.run(Request()) >2. How and where do I delete (remove?) a session. I'm guessing I > should put that code in the class for the last page of the > application. What code and where? In the page_display method > (and after ctx.run_template())? If your application contains a "logout" button, you could do it in the page_process function like this: if ctx.req_equals('logout'): ctx.remove_session() ctx.set_page('login') If you have a page from which the application can go no further, you could remove the session on entering the page (the user will never leave the page - but reloading the page will take them back to the begining). Note that you will need something to clean up abandoned sessions (the client closes their browser window without signing off, etc) - the simplest is a cron job (if you are using unix) or script that is run once a day that deletes any files older than a day from the session directory. This isn't necessary with other types of session application (the session server discards old sessions itself, and the hidden field sessions are saved by the client). >3. And what does each page class need to do in order to ensure that > it is using the correct session data/state for the current > request? I'm not sure what you mean here? It should be the correct session data, because a session is unique to a user (although they can do silly things like creating another window or hitting the back key). >I need to understand the order and conditions under which page >object methods page_process, page_enter, page_leave, and >page_display are called. Trace methods in my app and reading >section "4.1 Albatross Application Model" of the manual have me >less than enlightened. Is there any place I can look for more >explanation on the processing model that Albatross follows? For a page class called "blah", blah.page_enter() is called once after the previous page class calls ctx.set_page('blah'), and blah.page_display() is then called (and called each time the page is redisplayed - on reload, for example). When the user submits some data, blah.page_process() is called. page_process() can act on the data, save it, or request the application to move to a new page (ctx.set_page()). If the application remains on the "blah" page, blah.page_display() is called. If set_page() was called, blah.page_leave() is called, and process starts again with the new page class. Note that you don't need to provide all four methods - if not provided, they default to sensible actions in each case. In page_enter(), you would put one time initialisation (setting default values for form fields for example). def page_enter(ctx): ctx.locals.diagnostic = '' ctx.locals.whatever = load_whatever() ctx.add_session_vars('whatever') In page_display(), you might initialise more form fields (ones derived from external data, maybe), for example: def page_display(ctx): ctx.locals.load_setting_name = ctx.locals.settings.get_current_name() return ctx.run_template('change_parameters.html') In page_process(), you act on the user's form submission: def page_process(ctx): if ctx.req_equals('submit'): if ctx.locals.username == '': ctx.locals.diagnostic = 'You must enter a username' else: ctx.locals.diagnostic = '' In page_leave(), you might perform cleanup: def page_leave(ctx): ctx.remove_session_vars('whatever') Does that help? -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From dkuhlman at cutter.rexx.com Thu Jun 20 13:02:34 2002 From: dkuhlman at cutter.rexx.com (Dave Kuhlman) Date: Wed, 19 Jun 2002 20:02:34 -0700 Subject: [albatross-users] Session management how-to? In-Reply-To: <20020619011148.3B6FF38F5A@coffee.object-craft.com.au>; from andrewm@object-craft.com.au on Wed, Jun 19, 2002 at 11:11:48AM +1000 References: <20020618173140.A84176@cutter.rexx.com> <20020619011148.3B6FF38F5A@coffee.object-craft.com.au> Message-ID: <20020619200234.A46789@cutter.rexx.com> Andrew - > > Does that help? Yes it did. Thanks much. I don't quite have the intuitions for the Albatross process model down yet. Your message, notes, comments are helping quite a bit. I've got my simple stuff working. Tomorrow, I'm on to something a bit more complex and challenging. I'm also writing up a few notes, as I learn things, on how-to do things in Albatross. I've attached what I've done so far below. This is preliminary, needless to say; I'm still learning Albatross. But, if you you have any comments, I'm interested. And, if you should feel that this would be of use to other Albatross users (after a bit more work, of course), let me know. - Dave ============================================================= Albatross How-to for Beginners Contents: * Introduction * How-to Structure an Object-based Application * How-to Pass a Value to the Presentation * How-to Pass a Value to the Controller * How-to Manage Sessions Back to top _________________________________________________________________ Introduction This document explains how to do a number of simple tasks with Albatross. It is hoped that it will get a beginning Albatross user past a number of early questions and problems so that s/he can move on to more complex tasks. Back to top _________________________________________________________________ How-to Structure an Object-based Application This section describes the structure of an object-based application. It can be used as a "template" for creating an application. An object-based application is one 1. Create the presentation -- Create an HTML file for each page. This is the Albatross template file. 2. Create the controller -- Create a Python script. This script will contain the following items: 3. Import the needed Albatross classes. For an object-based application, the following are appropriate: from albatross import SimpleSessionApp, SessionAppContext 4. Define a class for each page in the application. Here is a sample: class Page2: name = 'page2' def page_process(self, ctx): if ctx.req_equals('button_1'): if ctx.get_value('next_page') == 'page3': ctx.set_page('page3') o o o def page_enter(self, ctx): o o o def page_leave(self, ctx): o o o def page_display(self, ctx): o o o ctx.run_template('page2.html') 5. Define a context class as a subclass of SessionAppContext. Here is a sample: class AppContext(SessionAppContext): def __init__(self, app): SessionAppContext.__init__(self, app) 6. Define an application class as a subclass of SimpleSessionApp. The constructor should call the constructor of the superclass and register each page (class) in the application. Also provide a create_context method that creates and returns an instance of your context class. Here is an example: class App(SimpleSessionApp): def __init__(self): SimpleSessionApp.__init__(self, base_url = 'dispatch.py', template_path = '.', start_page = 'page1', secret = 'tomato', session_appid = 'sampleapp') for page_class in (Page1, Page2, Page3): self.register_page(page_class.name, page_class()) def create_context(self): return AppContext(self) 7. Create the "main" script. Here is a sample: if __name__ == '__main__': app = App() app.run(Request()) Back to top _________________________________________________________________ How-to Pass a Value to the Presentation This technique enables you to pass a value from the controller (the Python script) to the presentation (the HTML file/template). 1. In the controller (i.e. in the Python script), add the value to the the locals in the context. Here is a sample of the page_display method in the class defined for the page: class Page1: name = 'page1' def page_display(self, ctx): ctx.locals.variable_1 = 'a sample value' ctx.locals.variable_2 = 'another value' ctx.run_template('page1.html') 2. In the presentation (i.e. the HTML page), use an Albatross tag to "capture" the value from the context. Here is a sample tag:

Value #1:

Value #2:

Back to top _________________________________________________________________ How-to Pass a Value to the Controller This technique enables you to capture input from the presentation (i.e. from the end-user at the Web browser) and pass those values back to the controller (the Python script). 1. Add "input" items to the presentation (the HTML template):

Enter your name:

Enter your name:

Note that the first item (user_name) allows you to pass a value to the presentation from the controller. The second item (user_phone) does not. 2. Capture the entered values in the controller. Here is a sample page_display method: class Page2: name = 'page1' def page_display(self, ctx): ctx.run_template('page1.html') user_name = ctx.locals.user_name user_phone = ctx.locals.user_phone # Do something with user_name and user_phone. o o o Back to top _________________________________________________________________ How-to Manage Sessions 1. How-to create a session -- Albatross does this for you automatically. If the request from the browser contains information about an existing session, that session is used, otherwise Albatross creates a new session. 2. How-to remove a session -- You will need to explicitly do this. (Albatross does not do this automatically.) If you have a page from which the application can go no further, you could remove the session on entering the page (the user will never leave the page - but reloading the page will take them back to the beginning). Here is an example: class FinalPage: def page_enter(self, ctx): ctx.remove_session() Or, if the final page of your application contains a "Logout" or "Exit" button, you can remove the session in the page_process method of the class for that page like this: class FinalPage: def page_process(self, ctx): # Check for the logout button. if ctx.req_equals('logout'): ctx.remove_session() # Send the user back to the login page. ctx.set_page('login') 3. How-to save session state across pages within the application -- In order to direct Albatross to do this, you will "register" the variables that you want saved. Do this by calling add_session_vars, passing the names of the variables to be saved. Here is an example: class Page1: def page_enter(self, ctx): ctx.add_session_vars('user_name', 'user_phone') Additional notes on session management: * In order to run a session based application, you must start-up an Albatross session server. The session-server sub-directory in the Albatross distribution, contains an implementation of a session server (al-session-daemon). * If your application inherits it context and application classes from SimpleSessionApp and SessionAppContext then Albatross stores and saves session information in files in the local file system. * In contrast, if your application inherits it context and application classes from SimpleSessionFileApp and SessionFileAppContext then Albatross stores and saves session information in the session server, i.e. in memory in the session server daemon. Note that if you change from memory-based session storage to file-based storage, you will need to modify the call to the application super class (). Add the session_dir keyword argument, with the directory (a string) where you want Albatross to store session state. _________________________________________________________________ -- Dave Kuhlman dkuhlman at rexx.com http://www.rexx.com/~dkuhlman From andrewm at object-craft.com.au Thu Jun 20 13:41:55 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Thu, 20 Jun 2002 13:41:55 +1000 Subject: [albatross-users] Session management how-to? In-Reply-To: Your message of "Wed, 19 Jun 2002 20:02:34 MST." <20020619200234.A46789@cutter.rexx.com> Message-ID: <20020620034155.177C538F5A@coffee.object-craft.com.au> >Yes it did. Thanks much. I don't quite have the intuitions for >the Albatross process model down yet. Your message, notes, >comments are helping quite a bit. I've got my simple stuff >working. Tomorrow, I'm on to something a bit more complex and >challenging. Shout if you get stuck. >I'm also writing up a few notes, as I learn things, on how-to do >things in Albatross. I've attached what I've done so far below. >This is preliminary, needless to say; I'm still learning Albatross. >But, if you you have any comments, I'm interested. And, if you >should feel that this would be of use to other Albatross users >(after a bit more work, of course), let me know. This is one of the areas in which our documentation is week - introducing new users to the "albatross way". I've always found this one of the hardest areas of documentation: you need to know a system thoroughly to be able to document it, but you need to be able to think like someone who is approaching it for the first time. Chapter 4, "Guide to Building Applications" is probably the chapter that comes closest to covering the information you were looking for. I like your How-to - we may be able to put it up on our web site (appropriately credited, of course) if you would like? >============================================================= > > > > Albatross How-to for Beginners > > Contents: > * Introduction > * How-to Structure an Object-based Application > * How-to Pass a Value to the Presentation > * How-to Pass a Value to the Controller > * How-to Manage Sessions > > Back to top > _________________________________________________________________ > >Introduction > > This document explains how to do a number of simple tasks with > Albatross. It is hoped that it will get a beginning Albatross user > past a number of early questions and problems so that s/he can move on > to more complex tasks. > Back to top > _________________________________________________________________ > >How-to Structure an Object-based Application > > This section describes the structure of an object-based application. > It can be used as a "template" for creating an application. > > An object-based application is one > 1. Create the presentation -- Create an HTML file for each page. This > is the Albatross template file. > 2. Create the controller -- Create a Python script. This script will > contain the following items: > 3. Import the needed Albatross classes. For an object-based > application, the following are appropriate: > from albatross import SimpleSessionApp, SessionAppContext > 4. Define a class for each page in the application. Here is a sample: > class Page2: > name = 'page2' > def page_process(self, ctx): > if ctx.req_equals('button_1'): > if ctx.get_value('next_page') == 'page3': > ctx.set_page('page3') > o > o > o > def page_enter(self, ctx): > o > o > o > def page_leave(self, ctx): > o > o > o > def page_display(self, ctx): > o > o > o > ctx.run_template('page2.html') > 5. Define a context class as a subclass of SessionAppContext. Here is > a sample: > class AppContext(SessionAppContext): > def __init__(self, app): > SessionAppContext.__init__(self, app) > 6. Define an application class as a subclass of SimpleSessionApp. The > constructor should call the constructor of the superclass and > register each page (class) in the application. Also provide a > create_context method that creates and returns an instance of your > context class. Here is an example: > class App(SimpleSessionApp): > def __init__(self): > SimpleSessionApp.__init__(self, > base_url = 'dispatch.py', > template_path = '.', > start_page = 'page1', > secret = 'tomato', > session_appid = 'sampleapp') > for page_class in (Page1, Page2, Page3): > self.register_page(page_class.name, page_class()) > def create_context(self): > return AppContext(self) > 7. Create the "main" script. Here is a sample: > if __name__ == '__main__': > app = App() > app.run(Request()) > > Back to top > _________________________________________________________________ > >How-to Pass a Value to the Presentation > > This technique enables you to pass a value from the controller (the > Python script) to the presentation (the HTML file/template). > 1. In the controller (i.e. in the Python script), add the value to > the the locals in the context. Here is a sample of the > page_display method in the class defined for the page: >class Page1: > name = 'page1' > def page_display(self, ctx): > ctx.locals.variable_1 = 'a sample value' > ctx.locals.variable_2 = 'another value' > ctx.run_template('page1.html') > 2. In the presentation (i.e. the HTML page), use an Albatross tag to > "capture" the value from the context. Here is a sample tag: >

Value #1:

>

Value #2:

> > Back to top > _________________________________________________________________ > >How-to Pass a Value to the Controller > > This technique enables you to capture input from the presentation > (i.e. from the end-user at the Web browser) and pass those values back > to the controller (the Python script). > 1. Add "input" items to the presentation (the HTML template): >

Enter your name:

>

Enter your name:

> Note that the first item (user_name) allows you to pass a value to the presentation from the controller. The second item (user_phone) > does not. > 2. Capture the entered values in the controller. Here is a sample > page_display method: >class Page2: > name = 'page1' > def page_display(self, ctx): > ctx.run_template('page1.html') > user_name = ctx.locals.user_name > user_phone = ctx.locals.user_phone > # Do something with user_name and user_phone. > o > o > o > > Back to top > _________________________________________________________________ > >How-to Manage Sessions > > 1. How-to create a session -- Albatross does this for you > automatically. If the request from the browser contains > information about an existing session, that session is used, > otherwise Albatross creates a new session. > 2. How-to remove a session -- You will need to explicitly do this. > (Albatross does not do this automatically.) If you have a page > from which the application can go no further, you could remove the > session on entering the page (the user will never leave the page - > but reloading the page will take them back to the beginning). Here > is an example: > class FinalPage: > def page_enter(self, ctx): > ctx.remove_session() > Or, if the final page of your application contains a "Logout" or > "Exit" button, you can remove the session in the page_process > method of the class for that page like this: > class FinalPage: > def page_process(self, ctx): > # Check for the logout button. > if ctx.req_equals('logout'): > ctx.remove_session() > # Send the user back to the login page. > ctx.set_page('login') > 3. How-to save session state across pages within the application -- > In order to direct Albatross to do this, you will "register" the > variables that you want saved. Do this by calling > add_session_vars, passing the names of the variables to be saved. > Here is an example: > class Page1: > def page_enter(self, ctx): > ctx.add_session_vars('user_name', 'user_phone') > > Additional notes on session management: > * In order to run a session based application, you must start-up an > Albatross session server. The session-server sub-directory in the > Albatross distribution, contains an implementation of a session > server (al-session-daemon). > * If your application inherits it context and application classes > from SimpleSessionApp and SessionAppContext then Albatross stores > and saves session information in files in the local file system. > * In contrast, if your application inherits it context and > application classes from SimpleSessionFileApp and > SessionFileAppContext then Albatross stores and saves session > information in the session server, i.e. in memory in the session > server daemon. Note that if you change from memory-based session > storage to file-based storage, you will need to modify the call to > the application super class (). Add the session_dir keyword > argument, with the directory (a string) where you want Albatross > to store session state. > > _________________________________________________________________ > >-- >Dave Kuhlman >dkuhlman at rexx.com >http://www.rexx.com/~dkuhlman >_______________________________________________ >Albatross-users mailing list >Albatross-users at object-craft.com.au >https://www.object-craft.com.au/cgi-bin/mailman/listinfo/albatross-users -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From djc at object-craft.com.au Sun Jun 23 19:47:43 2002 From: djc at object-craft.com.au (Dave Cole) Date: 23 Jun 2002 19:47:43 +1000 Subject: [albatross-users] Session management how-to? In-Reply-To: <20020619200234.A46789@cutter.rexx.com> References: <20020618173140.A84176@cutter.rexx.com> <20020619011148.3B6FF38F5A@coffee.object-craft.com.au> <20020619200234.A46789@cutter.rexx.com> Message-ID: > I'm also writing up a few notes, as I learn things, on how-to do > things in Albatross. I've attached what I've done so far below. > This is preliminary, needless to say; I'm still learning Albatross. > But, if you you have any comments, I'm interested. And, if you > should feel that this would be of use to other Albatross users > (after a bit more work, of course), let me know. This is enormously valuable. We are not able to do this as we are all too close to the code now. > ============================================================= > > > > Albatross How-to for Beginners > > Contents: > * Introduction > * How-to Structure an Object-based Application > * How-to Pass a Value to the Presentation > * How-to Pass a Value to the Controller > * How-to Manage Sessions This is excellent. Thanks for taking the time to document this. [snip] > How-to Manage Sessions > > 1. How-to create a session -- Albatross does this for you > automatically. If the request from the browser contains > information about an existing session, that session is used, > otherwise Albatross creates a new session. > 2. How-to remove a session -- You will need to explicitly do this. > (Albatross does not do this automatically.) If you have a page > from which the application can go no further, you could remove the > session on entering the page (the user will never leave the page - > but reloading the page will take them back to the beginning). Here > is an example: > class FinalPage: > def page_enter(self, ctx): > ctx.remove_session() > Or, if the final page of your application contains a "Logout" or > "Exit" button, you can remove the session in the page_process > method of the class for that page like this: > class FinalPage: > def page_process(self, ctx): > # Check for the logout button. > if ctx.req_equals('logout'): > ctx.remove_session() > # Send the user back to the login page. > ctx.set_page('login') If you use the session server then idle sessions are deleted automatically. The session server will handle multiple web servers. Session management is a non-issue for browser side sessions. [snip] > Additional notes on session management: > * In order to run a session based application, you must start-up an > Albatross session server. The session-server sub-directory in the > Albatross distribution, contains an implementation of a session > server (al-session-daemon). > * If your application inherits it context and application classes > from SimpleSessionApp and SessionAppContext then Albatross stores > and saves session information in files in the local file system. > * In contrast, if your application inherits it context and > application classes from SimpleSessionFileApp and > SessionFileAppContext then Albatross stores and saves session > information in the session server, i.e. in memory in the session > server daemon. Note that if you change from memory-based session > storage to file-based storage, you will need to modify the call to > the application super class (). Add the session_dir keyword > argument, with the directory (a string) where you want Albatross > to store session state. Small correction; SimpleSessionFileApp and SessionFileAppContext saves sessions in the file system while SimpleSessionApp and SessionAppContext save sessions in the session server via TCP socket. - Dave -- http://www.object-craft.com.au From dan at grassi.org Tue Jun 25 10:59:27 2002 From: dan at grassi.org (Dan Grassi) Date: Mon, 24 Jun 2002 20:59:27 -0400 Subject: [albatross-users] Additions/help wanted? Message-ID: Hi, I just found Albatross and it looks like what I am striving for in the web application code I have been writing. My work is based on a portion of a very early WebWare but I did not like the direction it was going so I forked my own project. Currently the main area I am working on is form generation, validation and integration with a SQL (MySQL) database. I have a good amount done at this point and could work it into the Albatross framework. The question is: Are you interested in help/contributions in this area? Or should I plan on a seperate project that is an add-on that works with Albatross? For a little background: I have over 25 years of programming experience. I have good current experience with databases design and usage (Sybase & MySQL), C/C++ and my favorite: Python. I am also very familiar with web protocols and such and was technical director for a dot-com for a short time. I also have several web sites with one that gets over 500 unique visitors a day and serves about 6GB/mo. Thanks, Dan From djc at object-craft.com.au Tue Jun 25 21:16:10 2002 From: djc at object-craft.com.au (Dave Cole) Date: 25 Jun 2002 21:16:10 +1000 Subject: [albatross-users] Additions/help wanted? In-Reply-To: References: Message-ID: >>>>> "Dan" == Dan Grassi writes: Dan> Hi, I just found Albatross and it looks like what I am striving Dan> for in the web application code I have been writing. My work is Dan> based on a portion of a very early WebWare but I did not like the Dan> direction it was going so I forked my own project. You can never have too many projects :-) Dan> Currently the main area I am working on is form generation, Dan> validation and integration with a SQL (MySQL) database. I have a Dan> good amount done at this point and could work it into the Dan> Albatross framework. Dan> The question is: Are you interested in help/contributions in this Dan> area? Or should I plan on a seperate project that is an add-on Dan> that works with Albatross? It depends. I think that Andrew and I would have to see the code and discuss with you how it may fit inside Albatross or as an optional add-on to the main package. Does this seem like a good approach to you? We are trying to keep the toolkit small and modular. If what you are offering adds too much to the toolkit we might have to decide whether we like a small toolkit more than we like your code :-). Dan> For a little background: I have over 25 years of programming Dan> experience. I have good current experience with databases design Dan> and usage (Sybase & MySQL), C/C++ and my favorite: Python. I am Dan> also very familiar with web protocols and such and was technical Dan> director for a dot-com for a short time. I also have several web Dan> sites with one that gets over 500 unique visitors a day and Dan> serves about 6GB/mo. Cool. - Dave -- http://www.object-craft.com.au From tchur at optushome.com.au Wed Jun 26 05:13:29 2002 From: tchur at optushome.com.au (Tim Churches) Date: Wed, 26 Jun 2002 05:13:29 +1000 Subject: [albatross-users] Additions/help wanted? References: Message-ID: <3D18C0D9.A9F19788@optushome.com.au> Dave Cole wrote: > > >>>>> "Dan" == Dan Grassi writes: > Dan> Currently the main area I am working on is form generation, > Dan> validation and integration with a SQL (MySQL) database. I have a > Dan> good amount done at this point and could work it into the > Dan> Albatross framework. To me, as a user of Albatross, that sounds very interesting. Albatross is great but creating forms is still too much like hard work, and parameter-driven mechanisms for building forms on-the-fly would be great. Is that what you are working on. Given albatross's clean, light-weight, modular design, I think it would make a great base for such a facility. > > Dan> The question is: Are you interested in help/contributions in this > Dan> area? Or should I plan on a seperate project that is an add-on > Dan> that works with Albatross? > > It depends. I think that Andrew and I would have to see the code and > discuss with you how it may fit inside Albatross or as an optional > add-on to the main package. If Dan is working on what I think he is working on, it probably fits better as an optional add-on module, built on top of Albatross rather than part of it. But presumably Object Craft would be happy to host the code on the OC site and to promote it as an add-on to Albatross - provided it met OC's rigorous standards for elegance and aesthetics ;-) Dan, maybe you can tell us a bit more about the goals of your project. Sounds exciting to me. Tim C From gimbo at ftech.net Fri Jun 28 01:25:13 2002 From: gimbo at ftech.net (Andy Gimblett) Date: Thu, 27 Jun 2002 16:25:13 +0100 Subject: [albatross-users] Two questions (client-side production of static pages) Message-ID: <20020627152510.GA3979@andy.tynant.ftech.net> Hi there, First, let me say I've been using Albatross for a little while now to power my weblog (http://gimbo.org.uk/) and I really like it: it certainly seems to achieve the stated aim of staying "out of the way" and letting me get on with what I want to do in a reasonably obvious manner. I'm (currently) only using Albatross on the client-side. Specifically, I'm using its templating capabilities to build static pages which then get uploaded to my ISP's web server. There are a couple of things I've had problems with. I've fixed one (sort of), but the other leaves me stumped. The first question/point: I want to be able to produce output to a file, not just stdout (don't want to use redirection as using stdout for other purposes). Now, I've achieved this by patching ExecuteMixin and SimpleContext in the following "quick and dirty" manner: class ExecuteMixin: '''Manages a template execution context ''' def __init__(self, filehandle=sys.stdout): self.__macro_stack = [] self.__trap_stack = [] self.reset_content() self.outputfilehandle = filehandle def send_content(self, data): self.outputfilehandle.write(data) self.outputfilehandle.flush() class SimpleContext(NamespaceMixin, ExecuteMixin, ResourceMixin, TemplateLoaderMixin, StubRecorderMixin, StubSessionMixin): def __init__(self, template_path, outputfile=sys.stdout): import tags NamespaceMixin.__init__(self) ExecuteMixin.__init__(self, outputfile) ResourceMixin.__init__(self) TemplateLoaderMixin.__init__(self, template_path) apply(self.register_tagclasses, tags.tags) self.set_globals(_caller_globals(2)) This works for me, but I was wondering: - Can anyone think of a better way to achieve this? - Is this (or a better solution) something that could be folded into the offical distribution, so I needn't maintain my own fork? :-) It seems a useful capability to me. My second question, which I haven't been able to solve, regards macros. I have pages which are based on a master template, along these lines: master.html: Stuff stuff stuff Blah blah blah somepage.html: Foo bar, foo bar, foo bar... Make sense? Now, what I'd _really_ like is to have a number of templates which are used to build each page. In particular, a large chunk of master.html is a sidebar table which is rather large: I'd love to be able to break that out into a seperate template then bring it in in either master.html or better yet, somepage.html (then I could have a choice of sidebars for different pages, all of which use the same master). My instinct tells me there should be a way to do this but I haven't been able to find it. Can anyone clue me in? That's it - thanks again for a cool product. -Andy -- Andy Gimblett - Programmer - Frontier Internet Services Limited Tel: 029 20 820 044 Fax: 029 20 820 035 http://www.frontier.net.uk/ Statements made are at all times subject to Frontier's Terms and Conditions of Business, which are available upon request. From tchur at optushome.com.au Fri Jun 28 05:19:19 2002 From: tchur at optushome.com.au (Tim Churches) Date: Fri, 28 Jun 2002 05:19:19 +1000 Subject: [albatross-users] Two questions (client-side production of static pages) References: <20020627152510.GA3979@andy.tynant.ftech.net> Message-ID: <3D1B6537.6487D613@optushome.com.au> Andy Gimblett wrote: > I'm (currently) only using Albatross on the client-side. > Specifically, I'm using its templating capabilities to build static > pages which then get uploaded to my ISP's web server. There are a > couple of things I've had problems with. I've fixed one (sort of), > but the other leaves me stumped. > > The first question/point: I want to be able to produce output to a > file, not just stdout (don't want to use redirection as using stdout > for other purposes). Now, I've achieved this by patching ExecuteMixin > and SimpleContext in the following "quick and dirty" manner: ....8<.... > This works for me, but I was wondering: > > - Can anyone think of a better way to achieve this? > > - Is this (or a better solution) something that could be folded into > the offical distribution, so I needn't maintain my own fork? :-) > It seems a useful capability to me. I second the request for static page generation capabilities. I think I might have briefly discussed this with Dave and Andrew at some stage. In our application(s) [currently one, soon to be more], after specifying a set of parameters, various epidemiological analyses are run and a static results page is written to disc on the httpd server, and the user's browser is redirected to that page (which contains generated graphs and tables, and in the future machine-generated text). Users often want to refer back to the results of previous analyses, or to download the entire page and host them elsewhere, so it makes sense to keep the results hanging around on the server, especially since they are quite computationally expensive to produce. At the moment the layout of static results pages are all hard-coded, but it would make enormous sense to use the same Albatross templating facilities used elsewhere in teh app to generate these static pages as well. > > My second question, which I haven't been able to solve, regards > macros. I have pages which are based on a master template, along > these lines: > > master.html: > > > Stuff stuff stuff > > Blah blah blah > > > somepage.html: > > > > Foo bar, foo bar, foo bar... > > > > Make sense? > > Now, what I'd _really_ like is to have a number of templates which are > used to build each page. In particular, a large chunk of master.html > is a sidebar table which is rather large: I'd love to be able to break > that out into a seperate template then bring it in in either > master.html or better yet, somepage.html (then I could have a choice > of sidebars for different pages, all of which use the same master). Nested template processing (as opposed to macro expansion and header/footer inclusion within a single template)? Is that what you mean? Tim C Fellow Albatross User From dkuhlman at cutter.rexx.com Fri Jun 28 06:36:48 2002 From: dkuhlman at cutter.rexx.com (Dave Kuhlman) Date: Thu, 27 Jun 2002 13:36:48 -0700 Subject: [albatross-users] Session management how-to? In-Reply-To: ; from djc@object-craft.com.au on Sun, Jun 23, 2002 at 07:47:43PM +1000 References: <20020618173140.A84176@cutter.rexx.com> <20020619011148.3B6FF38F5A@coffee.object-craft.com.au> <20020619200234.A46789@cutter.rexx.com> Message-ID: <20020627133647.A60095@cutter.rexx.com> On Sun, Jun 23, 2002 at 07:47:43PM +1000, Dave Cole wrote: > > > I'm also writing up a few notes, as I learn things, on how-to do > > things in Albatross. I've attached what I've done so far below. > > This is preliminary, needless to say; I'm still learning Albatross. > > But, if you you have any comments, I'm interested. And, if you > > should feel that this would be of use to other Albatross users > > (after a bit more work, of course), let me know. > > This is enormously valuable. We are not able to do this as we are all > too close to the code now. Thanks for comments and encouragement. I've worked over this how-to document a bit more and made some additions. I also tried to incorporate your comments. The new version is appended below. And, I've attached a file containing the original source (HTML). You can also find it at my Web site (http://www.rexx.com/~dkuhlman/albatross_index.html). You are welcome to use it any way you think would be helpful. If you do decide to use it, let me know and I'll try to help with converting it to your source format. You use LaTeX2HTML, and I've used LaTeX/TeX only briefly, so this would be a good learning experience for me. [snip] > If you use the session server then idle sessions are deleted > automatically. The session server will handle multiple web servers. > Session management is a non-issue for browser side sessions. Ah ... I think I've got it. I made a correction to the doc. [snip] > > Small correction; SimpleSessionFileApp and SessionFileAppContext saves > sessions in the file system while SimpleSessionApp and > SessionAppContext save sessions in the session server via TCP socket. > Not sure that I understand this, but I added it to the doc. Thanks again for Albatross. - Dave K ================================================================ Albatross How-to for Beginners Contents: * Introduction * How-to Structure an Object-based Application * How-to Pass a Value to the Presentation * How-to Pass a Value to the Controller * How-to Create a Session-based Application * How-to Manage Sessions * How-to Convert an Object App to a Modular App * Transitions -- How-to Move From Page to Page Back to top _________________________________________________________________ Introduction This document explains how to do a number of simple tasks with Albatross. It is hoped that it will get a beginning Albatross user past a number of early questions and problems so that s/he can move on to more complex tasks. Back to top _________________________________________________________________ How-to Structure an Object-based Application This section describes the structure of an object-based application. It can be used as a "template" for creating an application. An object-based application is one 1. Create the presentation -- Create an HTML file for each page. This is the Albatross template file. 2. Create the controller -- Create a Python script. This script will contain the following items: 3. Import the needed Albatross classes. For an object-based application, the following are appropriate: from albatross import SimpleApp, SimpleAppContext 4. Define a class for each page in the application. Here is a sample: class Page2: name = 'page2' def page_process(self, ctx): if ctx.req_equals('button_1'): if ctx.get_value('next_page') == 'page3': ctx.set_page('page3') o o o def page_enter(self, ctx): o o o def page_leave(self, ctx): o o o def page_display(self, ctx): o o o ctx.run_template('page2.html') 5. Define a context class as a subclass of SessionAppContext. Here is a sample: class AppContext(SimpleAppContext): def __init__(self, app): SimpleAppContext.__init__(self, app) 6. Define an application class as a subclass of SimpleSessionApp. The constructor should call the constructor of the superclass and register each page (class) in the application. Also provide a create_context method that creates and returns an instance of your context class. Here is an example: class App(SimpleApp): def __init__(self): SimpleApp.__init__(self, base_url = 'dispatch.py', template_path = '.', start_page = 'page1', secret = 'tomato') for page_class in (Page1, Page2, Page3): self.register_page(page_class.name, page_class()) def create_context(self): return AppContext(self) 7. Create the "main" script. Here is a sample: if __name__ == '__main__': app = App() app.run(Request()) Back to top _________________________________________________________________ How-to Pass a Value to the Presentation This technique enables you to pass a value from the controller (the Python script) to the presentation (the HTML file/template). 1. In the controller (i.e. in the Python script), add the value to the the locals in the context. Here is a sample of the page_display method in the class defined for the page: class Page1: name = 'page1' def page_display(self, ctx): ctx.locals.variable_1 = 'a sample value' ctx.locals.variable_2 = 'another value' ctx.run_template('page1.html') 2. In the presentation (i.e. the HTML page), use an Albatross tag to "capture" the value from the context. Here is a sample tag:

Value #1:

Value #2:

Back to top _________________________________________________________________ How-to Pass a Value to the Controller This technique enables you to capture input from the presentation (i.e. from the end-user at the Web browser) and pass those values back to the controller (the Python script). 1. Add "input" items to the presentation (the HTML template):

Enter your name:

Enter your name:

Note that the first item (user_name) also allows you to pass a value from the controller to the presentation. The second item (user_phone) does not. 2. Capture the entered values in the controller. Here is a sample page_display method: class Page2: name = 'page1' def page_process(self, ctx): user_name = ctx.locals.user_name user_phone = ctx.locals.user_phone # Do something with user_name and user_phone. o o o Back to top _________________________________________________________________ How-to Create a Session-based Application This section describes how-to create an application that manages sessions and saves state across pages (responses) within each session. Let's suppose that you start with a simple object-based application as described above. In order to convert this simple application into a session-based one, you will need to do the following: 1. Import and inherit from SimpleSessionApp and SessionAppContext (instead of from SimpleApp and SimpleAppContext) as follows: from albatross import SimpleSessionApp, SessionAppContext 2. Define your context class as a subclass of SessionAppContext (instead of AppContext). For example: class AppContext(SessionAppContext): def __init__(self, app): SessionAppContext.__init__(self, app) 3. Define your application class as a subclass of SimpleSessionApp (instead of SimpleApp). Note that in addition to switching to the use of SimpleSessionApp, you will also need to add the keyword argument session_appid. Here is an example: class App(SimpleSessionApp): def __init__(self): SimpleSessionApp.__init__(self, base_url = 'dispatch.py', template_path = '.', start_page = 'page1', secret = 'tomato', session_appid = 'sampleapp') for page_class in (Page1, Page2, Page3): self.register_page(page_class.name, page_class()) def create_context(self): return AppContext(self) 4. Start the session server -- In order to run your session application, you will need to start a session server. Albatross provides a session server that runs as a daemon. al-session-daemon is in the subdirectory session-server of the Albatross distribution. Get help by typing: ./al-session-daemon -h And, here is an example of how to start it up: ./al-session-daemon -k mysessions.pid start Back to top _________________________________________________________________ How-to Manage Sessions In this section, we explain how to control sessions from within your application. In particular, we'll describe how to create a new session and how to remove a session (e.g. when one of your end-users finishes with your application, and how to save state (values) across pages within a session. 1. How-to create a session -- Albatross does this for you automatically. If the request from the browser contains information about an existing session, that session is used, otherwise Albatross creates a new session. 2. How-to remove a session -- Albatross will delete idle sessions for you automatically. However, if you want your end users to be able to logout or exit from your application, for example, so that they can start a new session, then you will need to explicitly remove the session. For example, suppose you have a page from which the application can go no further. You could remove the session on entering the page. The user will never leave the page, but reloading the page will take them back to the beginning. Here is an example: class FinalPage: def page_enter(self, ctx): ctx.remove_session() Or, if the final page of your application contains a "Logout" or "Exit" button, you can remove the session in the page_process method of the class for that page like this: class FinalPage: def page_process(self, ctx): # Check for the logout button. if ctx.req_equals('logout'): ctx.remove_session() # Send the user back to the login page. ctx.set_page('login') 3. How-to save session state across pages within the application -- In order to direct Albatross to do this, you will "register" the variables that you want saved. Do this by calling add_session_vars, passing the names of the variables to be saved. Here is an example: class Page1: def page_enter(self, ctx): ctx.add_session_vars('user_name', 'user_phone') This tells Albatross to preserve these variables across pages. In Addition, you must also create these variables in the context. In Python code, the following will work: ctx.locals.user_name = name ctx.locals.user_phone = phone And, in HTML, an input item in a form will create the values. After doing this, you will be able to access these variables within the locals of the context object. For example in Python: name = ctx.locals.user_name phone = ctx.locals.user_phone And, since the values are in the local context, you will be able to reference these variables from your HTML code. For example: Additional notes on session management: * In order to run a session based application, you must start-up an Albatross session server. The session-server sub-directory in the Albatross distribution, contains an implementation of a session server (al-session-daemon). * If your application inherits its context and application classes from SimpleSessionApp and SessionAppContext then Albatross stores and saves session information in the session server via TCP socket. * In contrast, if your application inherits its context and application classes from SimpleSessionFileApp and SessionFileAppContext then Albatross stores and saves session information in files in the local file system. Note that if you change from memory-based session storage to file-based storage, you will need to modify the call to the application superclass (SimpleSessionFileApp). Add the session_dir keyword argument, with the directory (a string) where you want Albatross to store session state. Back to top _________________________________________________________________ How-to Convert an Object App to a Modular App First, let's make clear what we are trying to do here. We are going to convert an application whose controller is implemented with one class (object) definition for each page (i.e. an object-based application) into an application whose controller is implemented with one module (.py file) for each page (a modular application). Why would we do this? If the number of pages in your application has grown large, you may feel that you have too many classes. We are going to assume that you already have an object-based application 1. Create a "main" Python file in your application directory. Let's call it main.py. 2. In main.py, import ModularSessionApp and SessionAppContext: from albatross import ModularSessionApp, SessionAppContext If you want your session state stored in the local file system, rather than in the session server's memory, then use ModularSessionFileApp and SessionFileAppContext instead. For example: from albatross import ModularSessionFileApp, SessionFileAppContext And, if you want a non-session application, use the ModularApp class instead. 3. In main.py define a context class as a subclass of SessionAppContext (or SessionFileAppContext). Here is an example: class AppContext(SessionAppContext): def __init__(self, app): SessionAppContext.__init__(self, app) 4. In main.py define an application class as a subclass of ModularSessionApp (or ModularSessionFileApp). Here is an example: class App(ModularSessionApp): def __init__(self): ModularSessionApp.__init__(self, base_url = 'dispatch.py', module_path = '.', template_path = '.', start_page = 'page1', secret = 'apricot', session_appid = 'sampleapp') def create_context(self): return AppContext(self) 5. In main.py, define the "main" code, which should create and run the application instance. This code could look like the following: if __name__ == '__main__': app = App() app.run(Request()) 6. Now create a Python module for each page in your application. We will go through this process for a single page. Suppose you have a page page1.html (the presentation or view) and a class Page1 (the controller). Then, create a module called page1.py. 7. Copy the class that defines the controller for Page1 into page1.py. It might look something like the following: class Page1 name = 'page1' def page_process(self, ctx): if ctx.req_equals('button_1'): ctx.set_page('page2') elif ctx.req_equals('button_2'): ctx.set_page('page3') def page_display(self, ctx): ctx.run_template('page1.html') 8. Now, again in page1.py, (1) remove the class line and (2) out-dent the methods so that they are top-level functions in the module. Also, (3) remove the self argument from each function. It might now look something like this: name = 'page1' def page_process(ctx): if ctx.req_equals('button_1'): ctx.set_page('page2') elif ctx.req_equals('button_2'): ctx.set_page('page3') def page_display(ctx): ctx.run_template('page1.html') 9. Test your new modular application. Your conversion process is complete. Back to top _________________________________________________________________ Transitions -- How-to Move From Page to Page There are two parts to this question: 1. How do I test the conditions that determine which page is next? 2. How do I transition to the new page? We'll look at an example that tests several conditions. Here is an example from an object-based application: class Page1State: name = 'Page1' def page_process(self, ctx): if ctx.req_equals('Button_1') and \ ctx.get_value('next_page') == 'Page2' and \ ctx.get_value('user_name') != '' and \ ctx.get_value('user_code') > '0' and \ ctx.locals.user_type == 'important': ctx.set_page('Page2') elif ctx.req_equals('Button_2') and \ ctx.get_value('next_page') > 'Page3': ctx.set_page('Page3') The above example checks to determine whether Button_1 was pressed and, if so, checks the values of input items next_page, user_name, and user_code and session variable user_type before transitioning to Page2. Let's assume that user_type is a variable set in a previous page and that it was registered with add_session_vars. Notice that set_page in the context object is called to tell Albatross which page is next. This is the Albatross mechanism for transitioning from one page to the next. The argument to set_page is the name passed to register_page (for object-based applications) or the name of the Python module for the page (for modular applications). Now, here is an example from a modular application: def page_process(ctx): if ctx.req_equals('Button_0'): ctx.set_page('Page3') elif ctx.req_equals('Button_1') and \ ctx.get_value('next_page') == 'Page3': ctx.set_page('Page3') elif ctx.req_equals('Button_2') and \ ctx.get_value('next_page') == 'Page4': ctx.set_page('Page4') elif ctx.req_equals('Button_3'): ctx.set_page('Page3') Notice that this second example (from the modular application) is similar to the first example (from the object-based application), except that there are top-level functions in a module instead of methods in a class. Back to top _________________________________________________________________ Last update: 6/27/02 Dave Kuhlman dkuhlman at rexx.com http://www.rexx.com/~dkuhlman -- Dave Kuhlman dkuhlman at rexx.com http://www.rexx.com/~dkuhlman -------------- next part -------------- A non-text attachment was scrubbed... Name: alba.zip Type: application/x-zip-compressed Size: 2814 bytes Desc: not available URL: From gimbo at ftech.net Fri Jun 28 06:38:21 2002 From: gimbo at ftech.net (Andy Gimblett) Date: Thu, 27 Jun 2002 21:38:21 +0100 Subject: [albatross-users] Two questions (client-side production of static pages) In-Reply-To: <3D1B6537.6487D613@optushome.com.au> References: <20020627152510.GA3979@andy.tynant.ftech.net> <3D1B6537.6487D613@optushome.com.au> Message-ID: <20020627203821.GA6066@andy.tynant.ftech.net> On Fri, Jun 28, 2002 at 05:19:19AM +1000, Tim Churches wrote: > I second the request for static page generation capabilities. I > think I :-) It seems like a fairly obvious extension. To be honest I was suprised it wasn't there "out of the box". But I guess that's what us pesky users are for. ;-) > Nested template processing (as opposed to macro expansion and > header/footer inclusion within a single template)? Is that what you > mean? Um... Yeah, I guess so. If master.html could bring in sidebar.html that would basically do it. Although if somepage.html could specify _which_ sidebar.html to bring in somehow, that'd be good too. Not critical, but good. -Andy -- Andy Gimblett - Programmer - Frontier Internet Services Limited Tel: 029 20 820 044 Fax: 029 20 820 035 http://www.frontier.net.uk/ Statements made are at all times subject to Frontier's Terms and Conditions of Business, which are available upon request. From dkuhlman at cutter.rexx.com Fri Jun 28 07:11:07 2002 From: dkuhlman at cutter.rexx.com (Dave Kuhlman) Date: Thu, 27 Jun 2002 14:11:07 -0700 Subject: [albatross-users] Two questions (client-side production of static pages) In-Reply-To: <20020627152510.GA3979@andy.tynant.ftech.net>; from gimbo@ftech.net on Thu, Jun 27, 2002 at 04:25:13PM +0100 References: <20020627152510.GA3979@andy.tynant.ftech.net> Message-ID: <20020627141106.B60095@cutter.rexx.com> On Thu, Jun 27, 2002 at 04:25:13PM +0100, Andy Gimblett wrote: > Hi there, > > First, let me say I've been using Albatross for a little while now to > power my weblog (http://gimbo.org.uk/) and I really like it: it > certainly seems to achieve the stated aim of staying "out of the way" > and letting me get on with what I want to do in a reasonably obvious > manner. > > I'm (currently) only using Albatross on the client-side. > Specifically, I'm using its templating capabilities to build static > pages which then get uploaded to my ISP's web server. There are a > couple of things I've had problems with. I've fixed one (sort of), > but the other leaves me stumped. > > The first question/point: I want to be able to produce output to a > file, not just stdout (don't want to use redirection as using stdout > for other purposes). Now, I've achieved this by patching ExecuteMixin > and SimpleContext in the following "quick and dirty" manner: Sounds like you are asking for the template processing to be more localized and isolated from the rest of Albatross processing, so that it can be called independently and even used in non-Albatross applications. Are there other changes that should be made to make this more convenient? For example, should we be able to pass values to the template processor in some way other than ctx.locals. Well, I just looked, and the current mechanism seems pretty convenient just the way it is. Neat. I'm interesting in general text processing. So a template processing capability that can be called from Python code in other ways sounds like a good idea to me. [snip] > > My second question, which I haven't been able to solve, regards > macros. I have pages which are based on a master template, along > these lines: > > master.html: > > > Stuff stuff stuff > > Blah blah blah > > > somepage.html: > > > > Foo bar, foo bar, foo bar... > > > > Make sense? > > Now, what I'd _really_ like is to have a number of templates which are > used to build each page. In particular, a large chunk of master.html > is a sidebar table which is rather large: I'd love to be able to break > that out into a seperate template then bring it in in either > master.html or better yet, somepage.html (then I could have a choice > of sidebars for different pages, all of which use the same master). > > My instinct tells me there should be a way to do this but I haven't > been able to find it. Can anyone clue me in? Is this a request for "include" processing and an "al-include" tag? If so, you will need to define its semantics (processing). Perhaps something like: "Includes are inserted, recursively, before other template processing is performed." > > That's it - thanks again for a cool product. > Ditto from me. -- Dave Kuhlman dkuhlman at rexx.com http://www.rexx.com/~dkuhlman From gimbo at ftech.net Fri Jun 28 08:08:44 2002 From: gimbo at ftech.net (Andy Gimblett) Date: Thu, 27 Jun 2002 23:08:44 +0100 Subject: [albatross-users] Two questions (client-side production of static pages) In-Reply-To: <20020627141106.B60095@cutter.rexx.com> References: <20020627152510.GA3979@andy.tynant.ftech.net> <20020627141106.B60095@cutter.rexx.com> Message-ID: <20020627220844.GA6473@andy.tynant.ftech.net> On Thu, Jun 27, 2002 at 02:11:07PM -0700, Dave Kuhlman wrote: > Sounds like you are asking for the template processing to be more > localized and isolated from the rest of Albatross processing, so I'm not sure if I agree with that: see below. > that it can be called independently and even used in non-Albatross > applications. Are there other changes that should be made to make > this more convenient? For example, should we be able to pass > values to the template processor in some way other than ctx.locals. I haven't found using ctx.locals to be limiting, to be honest. It's pretty nicely general, isn't it? > Well, I just looked, and the current mechanism seems pretty > convenient just the way it is. Neat. I'm interesting in general > text processing. So a template processing capability that can be > called from Python code in other ways sounds like a good idea to > me. Yes, I'd agree that the current scheme works well. I don't think the template processing needs to be isolated from the rest of Albatross, and I say that because it's thus far the only aspect of the system I've needed or attempted to use, and I've had no problems using it in isolation. I think all that's required is a neat way to redirect output to an arbitrary stream rather than just sys.stdout (though that should of course be the default). > Is this a request for "include" processing and an "al-include" tag? I suppose so. I was really just asking if there was a way to do it, but if there isn't then yes, a request for such a feature would be the next logical step. :-) > If so, you will need to define its semantics (processing). Perhaps > something like: "Includes are inserted, recursively, before other > template processing is performed." OK, I'll have a think about this, unless I see someone else attack it first. :-) Cheers, Andy -- Andy Gimblett - Programmer - Frontier Internet Services Limited Tel: 029 20 820 044 Fax: 029 20 820 035 http://www.frontier.net.uk/ Statements made are at all times subject to Frontier's Terms and Conditions of Business, which are available upon request. From andrewm at object-craft.com.au Fri Jun 28 10:13:09 2002 From: andrewm at object-craft.com.au (Andrew McNamara) Date: Fri, 28 Jun 2002 10:13:09 +1000 Subject: [albatross-users] Two questions (client-side production of static pages) In-Reply-To: Your message of "Thu, 27 Jun 2002 16:25:13 +0100." <20020627152510.GA3979@andy.tynant.ftech.net> Message-ID: <20020628001309.420A138F5A@coffee.object-craft.com.au> I'm actually in the process of using Albatross to create a static web site also, so hopefully I already have the answers you are looking for. Mostly, it turns out, Dave has already provided the mechanism we require (or hooks to make it easier). >The first question/point: I want to be able to produce output to a >file, not just stdout (don't want to use redirection as using stdout >for other purposes). Now, I've achieved this by patching ExecuteMixin >and SimpleContext in the following "quick and dirty" manner: [snip] >This works for me, but I was wondering: > > - Can anyone think of a better way to achieve this? You should use the content trap mechamism, for example: ctx.push_content_trap() tmpl = ctx.load_template(filename) tmpl.to_html(ctx) ctx.flush_content() results = ctx.pop_content_trap() f = open(output_file, "w") f.write(results) f.close() [snip] >Now, what I'd _really_ like is to have a number of templates which are >used to build each page. In particular, a large chunk of master.html >is a sidebar table which is rather large: I'd love to be able to break >that out into a seperate template then bring it in in either >master.html or better yet, somepage.html (then I could have a choice >of sidebars for different pages, all of which use the same master). > >My instinct tells me there should be a way to do this but I haven't >been able to find it. Can anyone clue me in? Macro's can be nested, but you have to explicitly pass args through - you can do things like this: ... ... ... ... ... ... ... ... Note also that I keep my macros in separate files. My page generation scheme creates one SimpleContext object that is used by all pages. I first load the common macro templates, then all the pages: the macros are recorded by the SimpleContext object and are available to all pages. Actually, my scheme now goes beyond this - templates in sub-directories can override those defined higher up (I did this by implementing my own register_macro and get_macro methods on an object that inherits from SimpleContext). I'm also overriding the load_template() method and fiddling with the path on the way through to make work more intuitively with directory heirarchies. It's still very much a work in progress - but at some point I would like to make the script available. -- Andrew McNamara, Senior Developer, Object Craft http://www.object-craft.com.au/ From djc at object-craft.com.au Fri Jun 28 10:45:05 2002 From: djc at object-craft.com.au (Dave Cole) Date: 28 Jun 2002 10:45:05 +1000 Subject: [albatross-users] Two questions (client-side production of static pages) In-Reply-To: <20020627152510.GA3979@andy.tynant.ftech.net> References: <20020627152510.GA3979@andy.tynant.ftech.net> Message-ID: >>>>> "Andy" == Andy Gimblett writes: Andy> Hi there, First, let me say I've been using Albatross for a Andy> little while now to power my weblog (http://gimbo.org.uk/) and I Andy> really like it: it certainly seems to achieve the stated aim of Andy> staying "out of the way" and letting me get on with what I want Andy> to do in a reasonably obvious manner. It is nice to see someone using the template processing in a standalone manner. We wanted to make the application functionality optional. Andy> I'm (currently) only using Albatross on the client-side. Andy> Specifically, I'm using its templating capabilities to build Andy> static pages which then get uploaded to my ISP's web server. Andy> There are a couple of things I've had problems with. I've fixed Andy> one (sort of), but the other leaves me stumped. Andy> The first question/point: I want to be able to produce output to Andy> a file, not just stdout (don't want to use redirection as using Andy> stdout for other purposes). Now, I've achieved this by patching Andy> ExecuteMixin and SimpleContext in the following "quick and Andy> dirty" manner: Andy> class ExecuteMixin: Andy> '''Manages a template execution context Andy> ''' Andy> def __init__(self, filehandle=sys.stdout): Andy> self.__macro_stack = [] Andy> self.__trap_stack = [] Andy> self.reset_content() Andy> self.outputfilehandle = filehandle Andy> Andy> def send_content(self, data): Andy> self.outputfilehandle.write(data) Andy> self.outputfilehandle.flush() Andy> Andy> class SimpleContext(NamespaceMixin, ExecuteMixin, ResourceMixin, Andy> TemplateLoaderMixin, StubRecorderMixin, Andy> StubSessionMixin): Andy> def __init__(self, template_path, outputfile=sys.stdout): Andy> import tags Andy> NamespaceMixin.__init__(self) Andy> ExecuteMixin.__init__(self, outputfile) Andy> ResourceMixin.__init__(self) Andy> TemplateLoaderMixin.__init__(self, template_path) Andy> apply(self.register_tagclasses, tags.tags) Andy> self.set_globals(_caller_globals(2)) Andy> This works for me, but I was wondering: Andy> - Can anyone think of a better way to achieve this? Have you tried this: ctx.push_content_trap() # run template(s) html = ctx.pop_content_trap() If you refer to the request processing flow in: http://www.object-craft.com.au/projects/albatross/albatross/fig-presimpexec.html you will note that the execution of templates and tags generates a stream of content fragments which accumulate in the context. Inside the execution context there is a simple list of strings. When the context is flushed a simple string.join() is performed on that list. Calling push_content_trap() saves the current list of fragments on a stack and then clears the list. When you call pop_content_trap() the contents of the list and joined and returned and the previous fragment list is restored from the stack. This is used internally for arguments to macro expansion and sometimes for options to the select tag. Andy> - Is this (or a better solution) something that could be Andy> folded into the offical distribution, so I needn't maintain my Andy> own fork? :-) It seems a useful capability to me. Hopefully the content trap is what you need. http://www.object-craft.com.au/projects/albatross/albatross/mixin-execute.html Andy> My second question, which I haven't been able to solve, regards Andy> macros. I have pages which are based on a master template, Andy> along these lines: Andy> master.html: Andy> Andy> Andy> Stuff stuff stuff Andy> Andy> Blah blah blah Andy> Andy> Andy> somepage.html: Andy> Andy> Andy> Andy> Foo bar, foo bar, foo bar... Andy> Andy> Andy> Make sense? Andy> Now, what I'd _really_ like is to have a number of templates Andy> which are used to build each page. In particular, a large chunk Andy> of master.html is a sidebar table which is rather large: I'd Andy> love to be able to break that out into a seperate template then Andy> bring it in in either master.html or better yet, somepage.html Andy> (then I could have a choice of sidebars for different pages, all Andy> of which use the same master). Andy> My instinct tells me there should be a way to do this but I Andy> haven't been able to find it. Can anyone clue me in? Andrew has been working on something similar here. Currently the naming of macros is static and it looks like you need some kind of dynamic macro capability. The other way to do it might be to specify the sidebar when you expand outermost macro. master.html: Stuff stuff stuff Blah blah blah somepage.html: Foo bar, foo bar, foo bar... Or even somepage.html: Foo bar, foo bar, foo bar... Andy> That's it - thanks again for a cool product. Lets hope we can make it even more cool. - Dave -- http://www.object-craft.com.au From djc at object-craft.com.au Fri Jun 28 10:48:20 2002 From: djc at object-craft.com.au (Dave Cole) Date: 28 Jun 2002 10:48:20 +1000 Subject: [albatross-users] Two questions (client-side production of static pages) In-Reply-To: <20020627203821.GA6066@andy.tynant.ftech.net> References: <20020627152510.GA3979@andy.tynant.ftech.net> <3D1B6537.6487D613@optushome.com.au> <20020627203821.GA6066@andy.tynant.ftech.net> Message-ID: >>>>> "Andy" == Andy Gimblett writes: >> Nested template processing (as opposed to macro expansion and >> header/footer inclusion within a single template)? Is that what you >> mean? Andy> Um... Yeah, I guess so. If master.html could bring in Andy> sidebar.html that would basically do it. Although if Andy> somepage.html could specify _which_ sidebar.html to bring in Andy> somehow, that'd be good too. Not critical, but good. Yet another hokey way to do it: Stuff stuff stuff Blah blah blah Then the name of the sidebar is placed into the execution context before macro expansion: ctx.locals.sidebar_name = 'sidebar-with-bells.html' - Dave -- http://www.object-craft.com.au From djc at object-craft.com.au Fri Jun 28 10:57:13 2002 From: djc at object-craft.com.au (Dave Cole) Date: 28 Jun 2002 10:57:13 +1000 Subject: [albatross-users] Two questions (client-side production of static pages) In-Reply-To: <20020627141106.B60095@cutter.rexx.com> References: <20020627152510.GA3979@andy.tynant.ftech.net> <20020627141106.B60095@cutter.rexx.com> Message-ID: >>>>> "Dave" == Dave Kuhlman writes: Dave> Sounds like you are asking for the template processing to be Dave> more localized and isolated from the rest of Albatross Dave> processing, so that it can be called independently and even used Dave> in non-Albatross applications. Most of the templating can be used in this way - apart from the application functionality. Dave> Are there other changes that should be made to make this more Dave> convenient? For example, should we be able to pass values to Dave> the template processor in some way other than ctx.locals. Dave> Well, I just looked, and the current mechanism seems pretty Dave> convenient just the way it is. Neat. I'm interesting in Dave> general text processing. So a template processing capability Dave> that can be called from Python code in other ways sounds like a Dave> good idea to me. Most of the template functionality should already be available standalone. All of the "Templates User Guide" in the manual concerns using templates without Albatross application objects. Maybe we need to make this more clear in the manual. >> Now, what I'd _really_ like is to have a number of templates which >> are used to build each page. In particular, a large chunk of >> master.html is a sidebar table which is rather large: I'd love to >> be able to break that out into a seperate template then bring it in >> in either master.html or better yet, somepage.html (then I could >> have a choice of sidebars for different pages, all of which use the >> same master). >> >> My instinct tells me there should be a way to do this but I haven't >> been able to find it. Can anyone clue me in? Dave> Is this a request for "include" processing and an "al-include" Dave> tag? If so, you will need to define its semantics (processing). Dave> Perhaps something like: "Includes are inserted, recursively, Dave> before other template processing is performed." Andrew has been experimenting with a more dynamic way to specify macros. I expect he could give you a small overview of the path he has been following. - Dave -- http://www.object-craft.com.au From djc at object-craft.com.au Fri Jun 28 11:22:17 2002 From: djc at object-craft.com.au (Dave Cole) Date: 28 Jun 2002 11:22:17 +1000 Subject: [albatross-users] Session management how-to? In-Reply-To: <20020627133647.A60095@cutter.rexx.com> References: <20020618173140.A84176@cutter.rexx.com> <20020619011148.3B6FF38F5A@coffee.object-craft.com.au> <20020619200234.A46789@cutter.rexx.com> <20020627133647.A60095@cutter.rexx.com> Message-ID: >>>>> "Dave" == Dave Kuhlman writes: Dave> On Sun, Jun 23, 2002 at 07:47:43PM +1000, Dave Cole wrote: >> > I'm also writing up a few notes, as I learn things, on how-to do >> > things in Albatross. I've attached what I've done so far below. >> > This is preliminary, needless to say; I'm still learning >> Albatross. > But, if you you have any comments, I'm interested. >> And, if you > should feel that this would be of use to other >> Albatross users > (after a bit more work, of course), let me know. >> >> This is enormously valuable. We are not able to do this as we are >> all too close to the code now. Dave> Thanks for comments and encouragement. Dave> If you do decide to use it, let me know and I'll try to help Dave> with converting it to your source format. You use LaTeX2HTML, Dave> and I've used LaTeX/TeX only briefly, so this would be a good Dave> learning experience for me. The pain is mostly worth it. Of all the options for documentation I feel it is the least bad. :-) >> Small correction; SimpleSessionFileApp and SessionFileAppContext >> saves sessions in the file system while SimpleSessionApp and >> SessionAppContext save sessions in the session server via TCP >> socket. >> Dave> Not sure that I understand this, but I added it to the doc. If you open two browser windows and compare the following pages it should be a little clearer (look at the diagrams). http://www.object-craft.com.au/projects/albatross/albatross/pack-sessappcontext.html http://www.object-craft.com.au/projects/albatross/albatross/pack-sessfileappcontext.html The only difference between SessionFileAppContext and SessionAppContext is the mixin class which handles the loading and storing of sessions. Looking at the documentation for those mixin classes: http://www.object-craft.com.au/projects/albatross/albatross/mixin-ctx-file-sess.html http://www.object-craft.com.au/projects/albatross/albatross/mixin-ctx-sess.html you can see that one of them talks to the session server while the other uses the local file store. A major goal in Albatross was to allow users to extend and replace functionality which did not suit them while retaining that which did. They way that this achieved was through a set of classes which were designed to be mixed together. Chapter 7 (Mixin Class Reference) of the manual is organised by mixin class. In each mixin class section is a description of each variant of that mixin class. For example section 7.6 describes the SessionContextMixin class of mixin. http://www.object-craft.com.au/projects/albatross/albatross/mixin-ctxsession.html In section 7.6 are all of the actual mixins which you can use for that function. The intention of Albatross is that you can add your own mixins to the set and then combine them in interesting ways to go beyond the offerings in chapter 8 (Prepackaged Application and Execution Context Classes). - Dave -- http://www.object-craft.com.au