A dynamic class repository
As part of my workflow project, I came across an interesting problem. Transition entities are modelled as classes derived from a base ActionDef class, because each action in the system needs to have its own custom code. As the system grows, I needed to design a repository for such classes.
The easy way to implement the repository is to put everything inside a package. It's reasonably scalable; a package can easily hold a lot of classes. But at some point, the package will become harder to maintain. There are other problems also. The application is designed to work as a long-running server. Shutting down the server to add new classes should not be required; instead, new classes should be added or redefined dynamically.
At this point, I started to contemplate how to design a dynamic Python class repository, in a safe and clean way. One simple way is to use a database to store the code for the class. At first, I was concerned that this would be a huge security problem; but then I realized that no matter what I did, code would have to be retrieved from the repository anyway, and a database would be no worse by itself than any other alternative. But there are some real issues with databases; the biggest problem is that it's not convenient to maintain, and also, not compatible with some standard code development practices, such as versioning repositories (I'm using Subversion).
After giving up on the database idea, I decided to keep it really simple, and use a standard file-based class repository. A class factory function gets the name of the desired class and looks after it in the repository. It loads the source file that has the same name of the class, and returns an instance of the class for the application to work. Relevant code goes like this:
The file based repository is simple, and also more convenient to work with than the database. But it still far from a ideal solution, and I'm still looking for improvements. One of the ideas is to include native support for Subversion in the repository code itself, using the Python Subversion bindings. Instead of a file read, I could checkout the latest version from the repository whenever required; it may be slow, though, so it's something to be carefully tested.
Another issue is that class references are passed as strings, instead of pure Python symbols. This is needed because all references have to be resolved at runtime by reading the source code on the fly. Also, as each class is defined into its own source file, there is no way for one class to refer to any other. The resulting code does read as nicely as it could. For example, the following code snippet shows a task definition class that holds a reference to a process definition:
I am looking into ways to allow one to write this reference in one of the forms below:
or
In the first case, the idea is to use the __getattribute__ magic function to capture attribute access to the ProcessLibrary object. It's tricky, and perhaps a little bit dangerous, because __getattribute__ imposes some limitations on what can be done. It allows the code to look as a pure Python attribute access, which improves readability; but on the other hand, it hides too much magic from the users, which may not be the best thing to do.
In the later example, the idea is to implement a import hook to create a pseudo-package of sorts. The problem with this approach is that Python's import mechanism is not well documented, and it's not clear what is the preferred way to implement an import hook.
In both cases, to avoid problems with circular references, it may be necessary to move the code from the class body to the __init__ code. There are also other projects that suffer from the same problem (referencing class names with strings); SQLObject and ctypes comes to mind. Finding a good and generic solution for the workflow library may also be helpful for these projects.
The easy way to implement the repository is to put everything inside a package. It's reasonably scalable; a package can easily hold a lot of classes. But at some point, the package will become harder to maintain. There are other problems also. The application is designed to work as a long-running server. Shutting down the server to add new classes should not be required; instead, new classes should be added or redefined dynamically.
At this point, I started to contemplate how to design a dynamic Python class repository, in a safe and clean way. One simple way is to use a database to store the code for the class. At first, I was concerned that this would be a huge security problem; but then I realized that no matter what I did, code would have to be retrieved from the repository anyway, and a database would be no worse by itself than any other alternative. But there are some real issues with databases; the biggest problem is that it's not convenient to maintain, and also, not compatible with some standard code development practices, such as versioning repositories (I'm using Subversion).
After giving up on the database idea, I decided to keep it really simple, and use a standard file-based class repository. A class factory function gets the name of the desired class and looks after it in the repository. It loads the source file that has the same name of the class, and returns an instance of the class for the application to work. Relevant code goes like this:
def makeObjFromName(self, name, expectedClass):
'''
Creates a new instance of classusing the process library
Searchs the pathlist for a file. If the file exists, executes
its content. It is assumed that the source file contains a
class with the same name as of the source file (without the .py
extension, of course). For example:
file name = pdCreateNewUser.py -> class name = pdCreateNewuser
If the file does not exist, or if there is no symbol with the
correct name inside the file, it will raise a NameError.
If the file exists, and the symbol is define, it checks if the
symbol is bound to a subclass of the expectedClass. If not,
it raises a TypeError. If the class is correct, the object is
automatically instantiated and returned.
'''
for path in self.pathlist:
filename = os.path.join(path, name+'.py')
print "** trying " + filename
if os.path.isfile(filename):
execfile(filename)
try:
print "** executed!"
obj = locals().get(name)
if isclass(obj) and issubclass(obj, expectedClass):
print "** found!"
return obj()
else:
raise TypeError, 'Object %s is not from the ' 'expected class %s' % (name, expecteClass)
except:
break
raise NameError, 'Could not find class %s in the library' % name
The file based repository is simple, and also more convenient to work with than the database. But it still far from a ideal solution, and I'm still looking for improvements. One of the ideas is to include native support for Subversion in the repository code itself, using the Python Subversion bindings. Instead of a file read, I could checkout the latest version from the repository whenever required; it may be slow, though, so it's something to be carefully tested.
Another issue is that class references are passed as strings, instead of pure Python symbols. This is needed because all references have to be resolved at runtime by reading the source code on the fly. Also, as each class is defined into its own source file, there is no way for one class to refer to any other. The resulting code does read as nicely as it could. For example, the following code snippet shows a task definition class that holds a reference to a process definition:
class tdFillInvoice(TaskDef):
name = 'Fills the invoice form'
description = '''
Fills all the fields of the invoce form (...)
'''
processdef = getProcessDef('pdPurchaseItems')
actions = [
('adConfirm', None, None),
('adCancel', None, None),
('adDelegate', None, None),
('adPrint', None, ''),
('adSaveDraft', None, ''),
]
I am looking into ways to allow one to write this reference in one of the forms below:
processdef = ProcessLibrary.pdPurchaseItems
or
from ProcessLibrary import pdPurchaceItems
processdef = pdPurchaseItems
In the first case, the idea is to use the __getattribute__ magic function to capture attribute access to the ProcessLibrary object. It's tricky, and perhaps a little bit dangerous, because __getattribute__ imposes some limitations on what can be done. It allows the code to look as a pure Python attribute access, which improves readability; but on the other hand, it hides too much magic from the users, which may not be the best thing to do.
In the later example, the idea is to implement a import hook to create a pseudo-package of sorts. The problem with this approach is that Python's import mechanism is not well documented, and it's not clear what is the preferred way to implement an import hook.
In both cases, to avoid problems with circular references, it may be necessary to move the code from the class body to the __init__ code. There are also other projects that suffer from the same problem (referencing class names with strings); SQLObject and ctypes comes to mind. Finding a good and generic solution for the workflow library may also be helpful for these projects.
19 Comments:
At November 16, 2004 at 9:00 PM, Ian Bicking said…
py.path, http://codespeak.net/py , has code both for loading modules from arbitrary locations, and for loading code directly from a subversion repository.
At February 3, 2006 at 8:21 PM, Anonymous said…
great. thanks.
At February 15, 2007 at 8:10 AM, Anonymous said…
Great blog on 6700 case ppc. I've stumbled on a superb money making website. Linkreferral is free to join and drives traffic to your website in an inivitive way (the more sites you visit, the more links you get back to your website.)
I've only been a member of Linkreferral for aproximately 2 weeks but I have already seen the volume of people coming to my site double - if not treble.
Linkreferral is not only driving visitors to my website but as a result my affiliate sales income has doubled also.
I really cannot push this website enough. It is free and it is fantastic!! www.linkreferral.com is a must for money making opportunities online.
At March 7, 2007 at 12:38 AM, Anonymous said…
Hi all,
here is another challenging day. This morning it begin all really fast, my boy was a little ill and was awake earlier than the sun. After that I get busy to select a new template for my next web site, but then I realized it was more smart to search for a ecommerce shopping cart. The rest of the day is passing pretty fast and the works are going fast, I hope that this evening I can at last go to play f
ootball. I really need to get control over my body shape a little bit.
See you soon
Adam
At February 12, 2010 at 7:43 AM, Anonymous said…
Well, If you have ever thought of writing some script to automate those things that you are doing several times on a daily basis, then you have a great and easy way to automate the entir e process. It comes without saying that a few imacros and firefox add-ons can automate all actions related to a browser (Mozilla). If you would like to automate your system as such, then you will need some other script, simple commands can automate your system. Even a beginner will automate things using a simple software called as sikuli all you need to do is to tell Sikuli what to do by giving some screenshots and straightforward commands.
A GUI can be used with Sikuli. Sikuli is an open siurce scripting application that will use a combination of simple commands like click, type, wait and so on. There's no internal API support, it just searches the screen for the image within the screenshot-which implies that you'll be able to use it for anything. There is literally no limit on how you employ it to automate things.
This is too good to be true, however if you watch the following video, you will come to know that this is often very easy. If you visit their home page, you get a lot of tutorials and support; it can be a cake walk even for beginners. You can check the video as well as get the software at [url=http://technoages.com/operating-system/apple-mac-os/automate-everything-through-a-simple-script-make-your-computer-listen-to-you/]TechnoAges.com[/url]
At February 13, 2012 at 2:24 AM, Anonymous said…
Thank you for providing such a thoughtful A dynamic class repository post, I really enjoy to be here. Your have great insight about A dynamic class repository of your post. Your Python Notes blog is really excellent.
--------------------------
My website: Online Poker Bonus deals and Texas Hold'em Poker & Poker ohne einzahlung
At August 7, 2012 at 1:31 PM, pay per head horse racing said…
This blog is really helpful to me, Lots of idea I got from this site.
At February 25, 2013 at 12:20 PM, Anonymous said…
I’m not that much of a online reader to be honest
but your sites really nice, keep it up! I'll go ahead and bookmark your website to come back later. Many thanks
my weblog :: Read �
At March 9, 2013 at 10:58 AM, Anonymous said…
Howdy! I realize this is kind of off-topic but I needed to ask.
Does managing a well-established blog such as yours take a lot of work?
I am brand new to writing a blog but I do write in my diary everyday.
I'd like to start a blog so I can easily share my experience and thoughts online. Please let me know if you have any recommendations or tips for brand new aspiring blog owners. Appreciate it!
Review my web page; User:Ahmad5883
At March 9, 2013 at 4:54 PM, Anonymous said…
I just couldn't depart your web site prior to suggesting that I really loved the usual information a person supply for your visitors? Is going to be back incessantly to inspect new posts
Here is my page - Private krankenversicherung Direkt
my website :: private kv wechseln
At March 17, 2013 at 4:29 PM, Anonymous said…
Wow, that's what I was looking for, what a stuff! present here at this web site, thanks admin of this site.
my site :: http://datahub.io/user/qvfmartha
At March 17, 2013 at 4:29 PM, Anonymous said…
Wow, that's what I was looking for, what a stuff! present here at this web site, thanks admin of this site.
Visit my blog post - http://datahub.io/user/qvfmartha
At March 27, 2013 at 12:19 PM, Anonymous said…
Why users still make use of to read news papers when in this technological world
the whole thing is existing on net?
Review my web page ... schufafrei kredit
At March 28, 2013 at 4:59 PM, Anonymous said…
Hello, every time i used to check blog posts here in the early hours in the daylight, for the
reason that i like to learn more and more.
Also visit my website - http://www.realmath.de/wiki/index.php?title=Benutzer:Florida992
At April 2, 2013 at 6:35 AM, Anonymous said…
At this time I am going away to do my breakfast, once having my breakfast coming yet again to read more news.
Also visit my homepage - Extra resources
At April 7, 2013 at 4:57 AM, Anonymous said…
Thank you for any other informative web site. Where else could I get that kind of information written
in such a perfect manner? I have a challenge that I am just now
working on, and I've been at the glance out for such info.
Here is my weblog At Home jobs For women
At April 7, 2013 at 4:57 AM, Anonymous said…
Way cool! Some extremely valid points! I appreciate you writing this write-up and the rest of the site is
extremely good.
Feel free to visit my website ... Xfire - gaming simplified
At March 4, 2016 at 8:33 PM, Anonymous said…
ninest123 16.03
prada outlet, nike outlet, longchamp outlet, burberry outlet, gucci handbags, ralph lauren polo, cheap jordans, louis vuitton outlet, louis vuitton outlet online, oakley sunglasses, uggs on sale, louis vuitton outlet, tiffany jewelry, replica watches, ralph lauren outlet, michael kors outlet, longchamp outlet, cheap oakley sunglasses, ray ban sunglasses, michael kors handbags, replica watches, michael kors outlet online, oakley sunglasses, uggs on sale, louboutin shoes, christian louboutin, ray ban sunglasses, uggs outlet, nike free, christian louboutin, uggs outlet, tiffany jewelry, nike air max, oakley sunglasses, longchamp bags, uggs on sale, michael kors outlet online, michael kors outlet online, nike air max, louis vuitton handbags, oakley sunglasses, louis vuitton, ray ban sunglasses, louboutin uk, michael kors, tory burch outlet, burberry factory outlet, prada handbags
At March 4, 2016 at 8:35 PM, Anonymous said…
lunette oakley pas cher, nike roshe run pas cher, lululemon outlet, hollister uk, jordan pas cher, coach purses, lunette ray ban pas cher, nike tn pas cher, hogan sito ufficiale, abercrombie and fitch, new balance, longchamp soldes, nike blazer pas cher, true religion outlet, true religion outlet, michael kors, replica handbags, michael kors, sac guess pas cher, ray ban uk, nike air max, mulberry uk, vans pas cher, abercrombie and fitch UK, louboutin pas cher, nike air max pas cher, coach outlet store online, nike free pas cher, true religion jeans, polo lacoste pas cher, true religion outlet, nike air max uk, ralph lauren pas cher, kate spade outlet, longchamp pas cher, nike air force, polo ralph lauren uk, hermes pas cher, michael kors uk, north face uk, timberland pas cher, vanessa bruno pas cher, nike free, michael kors outlet online, coach outlet, nike air max uk, burberry pas cher, north face pas cher, converse
Post a Comment
<< Home