[Twisted-Python] an easy twisted application question
okay, so if i've got a tap with the following updateApplication method: def updateApplication(app, config): app.registry = registry.Registry() ... ... and i want to access that app.registry attribute from an arbitrary location, how do i do it? i seem to remember hearing that there was only one instance of Application in a process, so does that mean that there's some (forgive the Java-speak) static method defined on the Application module that will get the current running instance? thanks in advance, -phil
On Tue, Nov 11, 2003 at 02:03:39PM -0500, Phil Christensen wrote:
okay, so if i've got a tap with the following updateApplication method:
def updateApplication(app, config): app.registry = registry.Registry() ... ...
and i want to access that app.registry attribute from an arbitrary location, how do i do it?
i seem to remember hearing that there was only one instance of Application in a process, so does that mean that there's some (forgive the Java-speak) static method defined on the Application module that will get the current running instance?
The old way of doing this would be... from twisted.internet.app import theApplication theApplication.registry However, this bites. Newly written programs should implement makeService() instead of updateApplication(). As a bonus, purely service-based programs can easily and cleanly do things like the above: from twisted.application import service class RegistryService(service.Service): def __init__(self): self.registry = registry.Registry() def makeService(config): s = RegistryService() ... anotherS = SomeotherService() anotherS.setServiceParent(s) # Or s.setServiceParent(anotherS) ... return s # or return anotherS `s' can be the parent service of other services, in which case it can be accessed simply by looking up the parent service, or it could be a child service of something else, in which case it would be accessed via a call to getServiceNamed() on the appropriate parent. This avoids the need for globals and lets services/applications be more readily configurable alongside other services/applications (since neither will have global state that might interfer with the other). Jp
Okay, that answers another question I had, but I'm still not clear on how to get at that service object from a couple of places. For example, here's my Realm implementation: class InnerSpaceRealm: __implements__ = portal.IRealm def requestAvatar(self, avatarId, mind, *interfaces): if pb.IPerspective in interfaces: registry = ### how do i get this? avatar = UserPerspective(mind, registry.get(avatarId)) return pb.IPerspective, avatar, avatar.logout else: raise NotImplementedError("no interface") what's the right way to get that service object? this issue comes up again in my UserPerspective class, where i need to access that registry object during perspective_xxx methods... there is a part of me that just wants to use registry as a one-off class with a class variable that returns the current instance, but i don't like that part ;-)..... thanks again, -phil
Newly written programs should implement makeService() instead of updateApplication(). As a bonus, purely service-based programs can easily and cleanly do things like the above:
from twisted.application import service
class RegistryService(service.Service): def __init__(self): self.registry = registry.Registry()
def makeService(config): s = RegistryService() ... anotherS = SomeotherService() anotherS.setServiceParent(s) # Or s.setServiceParent(anotherS) ... return s # or return anotherS
`s' can be the parent service of other services, in which case it can be accessed simply by looking up the parent service, or it could be a child service of something else, in which case it would be accessed via a call to getServiceNamed() on the appropriate parent.
This avoids the need for globals and lets services/applications be more readily configurable alongside other services/applications (since neither will have global state that might interfer with the other).
Jp
On Tue, Nov 11, 2003 at 04:28:55PM -0500, Phil Christensen wrote:
Okay, that answers another question I had, but I'm still not clear on how to get at that service object from a couple of places.
For example, here's my Realm implementation:
class InnerSpaceRealm: __implements__ = portal.IRealm
def requestAvatar(self, avatarId, mind, *interfaces): if pb.IPerspective in interfaces: registry = ### how do i get this? avatar = UserPerspective(mind, registry.get(avatarId)) return pb.IPerspective, avatar, avatar.logout else: raise NotImplementedError("no interface")
what's the right way to get that service object?
Like so: class InnerSpaceRealm: __implements__ = portal.IRealm def __init__(self, service): self.service = service def requestAvatar(self, avatarId, mind, *interfaces): ... ;) There are other ways, but I'm sure you don't need me to point them out. The key is, just do the obvious thing here. There's no special way to manage this. Jp
Jp Calderone wrote:
;) There are other ways, but I'm sure you don't need me to point them out. The key is, just do the obvious thing here. There's no special way to manage this.
I might add that this is exactly the reason that Realm is an interface and not a class. Considering that "session logic container" has infinite variability in its implementation, the restrictions on how a Realm has to work are _really_ light.
On Tue, 11 Nov 2003, "Phil Christensen" <phil@bubblehouse.org> wrote:
class InnerSpaceRealm: __implements__ = portal.IRealm
def requestAvatar(self, avatarId, mind, *interfaces): if pb.IPerspective in interfaces: registry = ### how do i get this? avatar = UserPerspective(mind, registry.get(avatarId)) return pb.IPerspective, avatar, avatar.logout else: raise NotImplementedError("no interface")
what's the right way to get that service object?
Others have already said that the right way is to "push, not pull": give the service object as an argument to __init__. I wanted to add that the correct way to pass the registry to UserPerspective is probably much the same thing: class UserPerspective: # ... def setRegistry(self, registry): self.registry = registry class InnerSpaceRealm: __implements__ = portal.IRealm def __init__(self, registry): self.registry = registry def requestAvatar(self, avatarId, mind, *interfaces): if pb.IPerspective in interfaces: avatar = UserPerspective(mind, self.registry.get(avatarId)) avatar.setRegistry(self.registry) return pb.IPerspective, avatar, avatar.logout else: raise NotImplementedError("no interface")
On Tue, 11 Nov 2003, Jp Calderone <exarkun@intarweb.us> wrote:
from twisted.application import service
class RegistryService(service.Service): def __init__(self): self.registry =3D registry.Registry()
def makeService(config): s =3D RegistryService() ... anotherS =3D SomeotherService() anotherS.setServiceParent(s) # Or s.setServiceParent(anotherS) ... return s # or return anotherS
Almost correct. The idiomatic way is class SomeOtherService # .... do something interesting here def registry(self): return self.parent.getServiceNamed('registry') def makeService(config): s = RegistryService() s.setName('registry') anotherS = SomeOtherService() m = service.MultiService() s.setServiceParent(m) anotherS.setServiceParent(m) return m The trick is to have 's' and 'anotherS' completely symmetrical, and allow them to access each other. Everything else Jp said, including the part about "globals bad, explicit references good" has my whole-hearted blessing.
so i followed jp's advice, and my makeService method now looks like this: ###############code################# def makeService(config): registry = Registry() reg_service = RegistryService(registry) portal = Portal(auth.InnerSpaceRealm(reg_service)) checker = auth.RegistryChecker(registry) portal.registerChecker(checker) pb_service = internet.TCPServer(int(config['port']), pb.PBServerFactory(portal)) reg_service.setServiceParent(pb_service) return pb_service ###############code################# when i try to build my tap file now, i get ###############traceback################# Traceback (most recent call last): File "/Users/phil/Python/Twisted/bin/mktap", line 30, in ? run() File "/Users/phil/Python/Twisted/twisted/scripts/mktap.py", line 160, in run options.subOptions) File "/Users/phil/Python/Twisted/twisted/scripts/mktap.py", line 58, in makeService ser = mod.makeService(options) File "./inner/space/bigbang.py", line 24, in makeService reg_service.setServiceParent(pb_service) File "/Users/phil/Python/Twisted/twisted/application/service.py", line 116, in setServiceParent self.parent.addService(self) AttributeError: TCPServer instance has no attribute 'addService' ###############traceback################# i've tried this both ways, with pb_service as the parent, and with reg_service as the parent, with the same result. btw, i am working out of a freshly checked-out cvs directory, but i doubt that matters. thanks again for any help, -phil
Newly written programs should implement makeService() instead of updateApplication(). As a bonus, purely service-based programs can easily and cleanly do things like the above:
from twisted.application import service
class RegistryService(service.Service): def __init__(self): self.registry = registry.Registry()
def makeService(config): s = RegistryService() ... anotherS = SomeotherService() anotherS.setServiceParent(s) # Or s.setServiceParent(anotherS) ... return s # or return anotherS
`s' can be the parent service of other services, in which case it can be accessed simply by looking up the parent service, or it could be a child service of something else, in which case it would be accessed via a call to getServiceNamed() on the appropriate parent.
AHA! i needed to have my parent class subclass MultiService, right? so i tried this, and the tap built fine...hopefully it was the right thing (still testing)... -phil class RegistryService(service.MultiService): def __init__(self, registry): service.MultiService.__init__(self) self.registry = registry def makeService(config): registry = Registry() reg_service = RegistryService(registry) portal = Portal(auth.InnerSpaceRealm(reg_service)) checker = auth.RegistryChecker(registry) portal.registerChecker(checker) pb_service = internet.TCPServer(int(config['port']), pb.PBServerFactory(portal)) pb_service.setServiceParent(reg_service) return reg_service
On Wed, 12 Nov 2003, "Phil Christensen" <phil@bubblehouse.org> wrote:
so i followed jp's advice, and my makeService method now looks like this:
###############code################# def makeService(config): registry = Registry() reg_service = RegistryService(registry) portal = Portal(auth.InnerSpaceRealm(reg_service)) checker = auth.RegistryChecker(registry) portal.registerChecker(checker) pb_service = internet.TCPServer(int(config['port']), pb.PBServerFactory(portal)) reg_service.setServiceParent(pb_service) return pb_service
Don't use a TCPServer as a parent, use a multi-service m = service.MultiService() reg_service.setServiceParent(m) pb_service.setServiceParent(m) return m
participants (5)
-
Glyph Lefkowitz -
Jp Calderone -
Moshe Zadka -
Moshe Zadka -
Phil Christensen